pengurutan daftar case-insensitive, tanpa menurunkan hasil?

133

Saya punya daftar string seperti ini:

['Aden', 'abel']

Saya ingin menyortir item, tidak sensitif huruf besar / kecil. Jadi saya ingin mendapatkan:

['abel', 'Aden']

Tapi saya kebalikannya dengan sorted()atau list.sort(), karena huruf besar muncul sebelum huruf kecil.

Bagaimana saya bisa mengabaikan kasus ini? Saya telah melihat solusi yang melibatkan lebih rendah semua item daftar, tetapi saya tidak ingin mengubah kasus item daftar.

jamylak
sumber
Tutorial ini sangat membantu: docs.python.org/3/howto/sorting.html#sortinghowto
ady

Jawaban:

192

Di Python 3.3+ ada str.casefoldmetode yang dirancang khusus untuk pencocokan tanpa casing:

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

Dalam Python 2 gunakan lower():

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

Ini berfungsi untuk string normal dan unicode, karena keduanya memiliki lowermetode.

Dalam Python 2 ini berfungsi untuk campuran string normal dan unicode, karena nilai kedua tipe dapat dibandingkan satu sama lain. Namun, Python 3 tidak berfungsi seperti itu: Anda tidak dapat membandingkan string byte dan string unicode, jadi dalam Python 3 Anda harus melakukan hal yang waras dan hanya mengurutkan daftar satu jenis string.

>>> lst = ['Aden', u'abe1']
>>> sorted(lst)
['Aden', u'abe1']
>>> sorted(lst, key=lambda s: s.lower())
[u'abe1', 'Aden']
John Kugelman
sumber
11
Satu dapat menghindari fungsi lambda pulang pergi dengan (Python 3) menggunakan str.lowerfungsi umum sebagai sorted(lst, key=str.lower)atau (Python 2) menggunakan lowermetode stringmodul sebagai sorted(lst, key=string.lower). Satu juga dapat digunakan str.loweruntuk string dalam Python 2, tetapi kemudian harus digunakan unicode.loweruntuk unicodeobjek, sedangkan string.lowermenerima keduanya (yang, seperti yang Anda katakan, mungkin bukan benar-benar mode operasi "waras", meskipun).
Daniel Andersson
Ini tidak akan berfungsi untuk daftar seperti ['Z', 'B', 'a', 'b', 'A'], yang mirip dengan ['a', 'A', 'B', 'B', 'b', 'Z']. Huruf kapital 'B' muncul di depan huruf kecil 'b' karena sort Python () dan sortir () mempertahankan urutan asli ketika string cocok. Dalam hal ini, modal 'B' dianggap cocok dengan huruf kecil 'b' saat menggunakan casefold. Ini selalu terjadi jika Anda mengonversi case untuk membandingkan: diurutkan (spam, key = str.lower) atau diurutkan (spam, key = str.upper) atau diurutkan (spam, key = str.casefold).
PJ Singh
Coba solusi ini sebagai gantinya: stackoverflow.com/a/1098160/10668287 . Ini akan mengurutkan ['Aden', 'aden'] dengan benar sebagai ['aden', 'Aden'].
PJ Singh
46
>>> x = ['Aden', 'abel']
>>> sorted(x, key=str.lower) # Or unicode.lower if all items are unicode
['abel', 'Aden']

Dalam Python 3 stradalah unicode tetapi dalam Python 2 Anda dapat menggunakan pendekatan yang lebih umum ini yang berfungsi untuk keduanya strdan unicode:

>>> sorted(x, key=lambda s: s.lower())
['abel', 'Aden']
jamylak
sumber
Terima kasih. Saya tahu saya seharusnya menyebutkan ini sebelumnya, tapi saya pernah mendengar ada masalah dengan menggunakan metode ini pada string unicode (Py2). Apakah Anda tahu sesuatu tentang itu?
Semuanya unicode. Terima kasih! Satu pertanyaan lagi, bagaimana melakukannya pada daftar seperti ini:[['Aden'], ['abel']]
Apakah setiap daftar hanya memiliki satu item? Jika demikian, modifikasi sedikit ke:sorted(x,key=lambda i:i[0].lower())
jamylak
Yah, mungkin ada beberapa hal lain juga, yang seharusnya tidak digunakan untuk menyortir.
1
Tidak masalah, sepertinya saya salah, penyortiran tidak berfungsi untuk campuran string dan unicode, saya bingung dengan pertanyaan sebelumnya di mana tuple juga termasuk dalam pengurutan.
jamylak
10

Anda juga dapat mencoba ini untuk mengurutkan daftar di tempat:

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

Di python3 Anda bisa menggunakan

list1.sort(key=lambda x: x.lower()) #Case In-sensitive             
list1.sort() #Case Sensitive
utama
sumber
1

Saya melakukannya dengan cara ini untuk 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]

Maka Anda bisa memanggil fungsi ini:

sortCaseIns(yourListToSort)
Alexey Gorozhanov
sumber
0

Jenis case-insensitive, menyortir string pada tempatnya , dengan Python 2 OR 3 (diuji dengan Python 2.7.17 dan 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']

Kuncinya adalah key=str.lower. Inilah yang terlihat dari perintah-perintah itu hanya dengan perintah, untuk memudahkan penyalinan sehingga Anda dapat mengujinya:

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

Perhatikan bahwa jika string Anda adalah string unicode, (seperti u'some string'), maka hanya dalam Python 2 (BUKAN dalam Python 3 dalam kasus ini) x.sort(key=str.lower)perintah di atas akan gagal dan menghasilkan kesalahan berikut:

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

Jika Anda mendapatkan kesalahan ini, maka tingkatkan ke Python 3 di mana mereka menangani penyortiran unicode, atau mengonversi string unicode Anda menjadi string ASCII terlebih dahulu, menggunakan pemahaman daftar, seperti ini:

# 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)

Referensi:

  1. https://docs.python.org/3/library/stdtypes.html#list.sort
  2. Ubah string Unicode menjadi string dengan Python (berisi simbol tambahan)
  3. https://www.programiz.com/python-programming/list-comprehension
Gabriel Staples
sumber
-3

Coba ini

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)

Keluaran

['abel', 'Aden']

Fatamorgana
sumber
9
Solusi ini berlebihan dan tidak dapat dibaca ketika satu liner sudah mencukupi. Ini mungkin lebih dapat diterima dalam bahasa selain Python.
IceArdor