tri de liste insensible à la casse, sans mettre le résultat en minuscules?

133

J'ai une liste de chaînes comme celle-ci:

['Aden', 'abel']

Je veux trier les éléments, insensible à la casse. Alors je veux obtenir:

['abel', 'Aden']

Mais j'obtiens le contraire avec sorted()ou list.sort(), car les majuscules apparaissent avant les minuscules.

Comment puis-je ignorer le cas? J'ai vu des solutions qui impliquent de mettre en minuscules tous les éléments de la liste, mais je ne veux pas changer la casse des éléments de la liste.

Jamylak
la source
Ce tutoriel est très utile: docs.python.org/3/howto/sorting.html#sortinghowto
ady

Réponses:

192

Dans Python 3.3+, il existe une str.casefoldméthode spécialement conçue pour la correspondance sans casse:

sorted_list = sorted(unsorted_list, key=str.casefold)

Dans Python 2, utilisez lower():

sorted_list = sorted(unsorted_list, key=lambda s: s.lower())

Cela fonctionne pour les chaînes normales et unicode, car elles ont toutes les deux une lowerméthode.

En Python 2, cela fonctionne pour un mélange de chaînes normales et unicode, car les valeurs des deux types peuvent être comparées entre elles. Python 3 ne fonctionne pas comme ça, cependant: vous ne pouvez pas comparer une chaîne d'octets et une chaîne unicode, donc dans Python 3, vous devriez faire la bonne chose et trier uniquement les listes d'un type de chaîne.

>>> lst = ['Aden', u'abe1']
>>> sorted(lst)
['Aden', u'abe1']
>>> sorted(lst, key=lambda s: s.lower())
[u'abe1', 'Aden']
John Kugelman
la source
11
On peut éviter le roundtrip de la fonction lambda en (Python 3) en utilisant la str.lowerfonction générale as sorted(lst, key=str.lower)ou (Python 2) en utilisant la lowerméthode du stringmodule as sorted(lst, key=string.lower). On peut aussi utiliser str.lowerpour les chaînes en Python 2, mais il faudrait alors utiliser unicode.lowerpour les unicodeobjets, alors que l'on string.loweraccepte les deux (ce qui, comme vous le dites, n'est probablement pas vraiment un mode de fonctionnement "sain", cependant).
Daniel Andersson
Cela ne fonctionnerait pas pour une liste comme ['Z', 'B', 'a', 'b', 'A'], qui trie en ['a', 'A', 'B', 'b', «Z»]. Le «B» majuscule apparaît avant le «b» minuscule parce que sort () et sorted () de Python conservent l'ordre d'origine lorsque les chaînes correspondent. Dans ce cas, le «B» majuscule est considéré comme correspondant au «b» minuscule lors de l'utilisation de casefold. Cela se produit toujours si vous convertissez la casse pour comparer: triée (spam, clé = str.lower) ou triée (spam, clé = str.upper) ou triée (spam, clé = str.casefold).
PJ Singh le
Essayez plutôt cette solution: stackoverflow.com/a/1098160/10668287 . Il triera ['Aden', 'aden'] correctement comme ['aden', 'Aden'].
PJ Singh le
46
>>> x = ['Aden', 'abel']
>>> sorted(x, key=str.lower) # Or unicode.lower if all items are unicode
['abel', 'Aden']

Dans Python 3, strc'est unicode, mais dans Python 2, vous pouvez utiliser cette approche plus générale qui fonctionne à la fois pour stret unicode:

>>> sorted(x, key=lambda s: s.lower())
['abel', 'Aden']
Jamylak
la source
Je vous remercie. Je sais que j'aurais dû le mentionner auparavant, mais j'ai entendu dire qu'il y avait un problème avec l'utilisation de cette méthode sur une chaîne unicode (Py2). Savez-vous quelque chose à ce sujet?
Ils sont tous unicode. Merci! [['Aden'], ['abel']]
Chaque liste n'a-t-elle qu'un seul élément? Si c'est le cas, modifiez-le un peu pour:sorted(x,key=lambda i:i[0].lower())
jamylak
Eh bien, il peut également contenir d'autres éléments, qui ne devraient pas être utilisés pour le tri.
1
Peu importe, il semble que j'avais tort, le tri fonctionne pour un mélange de chaîne et d'unicode, j'ai été confondu avec une question précédente où les tuples étaient également inclus dans le tri.
jamylak
10

Vous pouvez également essayer ceci pour trier la liste sur place:

>>> x = ['Aden', 'abel']
>>> x.sort(key=lambda y: y.lower())
>>> x
['abel', 'Aden']
Ashwini Chaudhary
la source
3

En python3, vous pouvez utiliser

list1.sort(key=lambda x: x.lower()) #Case In-sensitive             
list1.sort() #Case Sensitive
Majeur
la source
1

Je l'ai fait de cette façon pour Python 3.3:

 def sortCaseIns(lst):
    lst2 = [[x for x in range(0, 2)] for y in range(0, len(lst))]
    for i in range(0, len(lst)):
        lst2[i][0] = lst[i].lower()
        lst2[i][1] = lst[i]
    lst2.sort()
    for i in range(0, len(lst)):
        lst[i] = lst2[i][1]

Ensuite, vous pouvez simplement appeler cette fonction:

sortCaseIns(yourListToSort)
Alexey Gorozhanov
la source
0

Tri insensible à la casse, tri de la chaîne en place , en Python 2 OU 3 (testé en Python 2.7.17 et Python 3.6.9):

>>> x = ["aa", "A", "bb", "B", "cc", "C"]
>>> x.sort()
>>> x
['A', 'B', 'C', 'aa', 'bb', 'cc']
>>> x.sort(key=str.lower)           # <===== there it is!
>>> x
['A', 'aa', 'B', 'bb', 'C', 'cc']

La clé est key=str.lower. Voici à quoi ressemblent ces commandes avec seulement les commandes, pour un copier-coller facile afin que vous puissiez les tester:

x = ["aa", "A", "bb", "B", "cc", "C"]
x.sort()
x
x.sort(key=str.lower)
x

Notez que si vos chaînes sont des chaînes Unicode, cependant (comme u'some string'), alors en Python 2 uniquement (PAS en Python 3 dans ce cas) la x.sort(key=str.lower)commande ci-dessus échouera et produira l'erreur suivante:

TypeError: descriptor 'lower' requires a 'str' object but received a 'unicode'

Si vous obtenez cette erreur, mettez à niveau vers Python 3 où ils gèrent le tri Unicode, ou convertissez d'abord vos chaînes Unicode en chaînes ASCII, en utilisant une compréhension de liste, comme ceci:

# for Python2, ensure all elements are ASCII (NOT unicode) strings first
x = [str(element) for element in x]  
# for Python2, this sort will only work on ASCII (NOT unicode) strings
x.sort(key=str.lower)

Références:

  1. https://docs.python.org/3/library/stdtypes.html#list.sort
  2. Convertir une chaîne Unicode en chaîne en Python (contenant des symboles supplémentaires)
  3. https://www.programiz.com/python-programming/list-comprehension
Gabriel Staples
la source
-3

Essaye ça

def cSort(inlist, minisort=True):
    sortlist = []
    newlist = []
    sortdict = {}
    for entry in inlist:
        try:
            lentry = entry.lower()
        except AttributeError:
            sortlist.append(lentry)
        else:
            try:
                sortdict[lentry].append(entry)
            except KeyError:
                sortdict[lentry] = [entry]
                sortlist.append(lentry)

    sortlist.sort()
    for entry in sortlist:
        try:
            thislist = sortdict[entry]
            if minisort: thislist.sort()
            newlist = newlist + thislist
        except KeyError:
            newlist.append(entry)
    return newlist

lst = ['Aden', 'abel']
print cSort(lst)

Production

['abel', 'Aden']

Mirage
la source
9
Cette solution est excessive et illisible lorsqu'une seule ligne suffit. Cela pourrait être plus acceptable dans un langage autre que Python.
IceArdor