Menggunakan Python 3.x, saya memiliki daftar string yang ingin saya lakukan semacam abjad alami.
Sortir alami: Urutan di mana file dalam Windows diurutkan.
Misalnya, daftar berikut ini diurutkan secara alami (apa yang saya inginkan):
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
Dan inilah versi "diurutkan" dari daftar di atas (apa yang saya miliki):
['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
Saya mencari fungsi sortir yang berperilaku seperti yang pertama.
python
sorting
python-3.x
berliku-liku
sumber
sumber
!1, 1, !a, a
. Satu-satunya cara untuk mendapatkan pengurutan seperti Windows adalah dengan menggunakanStrCmpLogicalW
fungsi Windows itu sendiri, karena tidak ada yang tampaknya telah mengimplementasikan kembali fungsi ini dengan benar (sumber akan dihargai). Solusi: stackoverflow.com/a/48030307/2441026Jawaban:
Ada perpustakaan pihak ketiga untuk ini di PyPI yang disebut natsort (pengungkapan penuh, saya penulis paket). Untuk kasus Anda, Anda dapat melakukan salah satu dari yang berikut:
Anda harus mencatat bahwa
natsort
menggunakan algoritma umum sehingga harus bekerja untuk hampir semua input yang Anda gunakan. Jika Anda ingin lebih detail tentang mengapa Anda dapat memilih perpustakaan untuk melakukan ini daripada menggulirkan fungsi Anda sendiri, periksa halamannatsort
dokumentasi Cara Kerja , khususnya Kasus Khusus Di Mana Saja! bagian.Jika Anda membutuhkan kunci penyortiran alih-alih fungsi penyortiran, gunakan salah satu dari rumus di bawah ini.
sumber
natsort
juga 'secara alami' menangani kasus beberapa angka yang terpisah dalam string. Barang bagus!Coba ini:
Keluaran:
Kode diadaptasi dari sini: Penyortiran untuk Manusia: Urutan Urut Alami .
sumber
return sorted(l, key)
bukanl.sort(key)
? Apakah itu untuk peningkatan kinerja atau hanya untuk menjadi lebih pythonic?re.split('([0-9]+)', '0foo')
kembali['', '0', 'foo']
. Karena itu, string akan selalu berada pada indeks genap dan bilangan bulat pada indeks ganjil dalam array.Berikut versi Mark Byer yang jauh lebih pythonic:
Sekarang fungsi ini dapat digunakan sebagai kunci dalam fungsi yang menggunakan itu, seperti
list.sort
,sorted
,max
, dllSebagai lambda:
sumber
Saya menulis sebuah fungsi berdasarkan http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html yang menambahkan kemampuan untuk tetap meneruskan parameter 'kunci' Anda sendiri. Saya memerlukan ini untuk melakukan semacam daftar alami yang berisi objek yang lebih kompleks (bukan hanya string).
Sebagai contoh:
sumber
natural_sort_key
, dan kemudian ketika menyortir daftar Anda dapat melakukan rantai kunci Anda, misalnya:list.sort(key=lambda el: natural_sort_key(el['name']))
Mari menganalisis data. Kapasitas digit semua elemen adalah 2. Dan ada 3 huruf dalam bagian literal yang sama
'elm'
.Jadi, panjang maksimal elemen adalah 5. Kita dapat meningkatkan nilai ini untuk memastikan (misalnya, menjadi 8).
Mengingat hal itu, kami punya solusi satu baris:
tanpa ekspresi reguler dan perpustakaan eksternal!
Penjelasan:
sumber
width = max(data, key=len)
untuk menghitung apa yang harus8
dimasukkan untuk di atas dan kemudian memasukkannya ke dalam format string dengan'{0:0>{width}}'.format(x, width=width)
Diberikan:
Mirip dengan solusi SergO, 1-liner tanpa perpustakaan eksternal adalah :
atau
Penjelasan:
Solusi ini menggunakan fitur kunci pengurutan untuk menentukan fungsi yang akan digunakan untuk pengurutan. Karena kita tahu bahwa setiap entri data didahului oleh 'elm', fungsi penyortiran dikonversi menjadi integer bagian dari string setelah karakter ke-3 (yaitu int (x [3:])). Jika bagian numerik dari data berada di lokasi yang berbeda, maka bagian fungsi ini harus berubah.
Bersulang
sumber
Ada banyak implementasi di luar sana, dan sementara beberapa telah mendekati, tidak ada yang cukup menangkap keanggunan python modern.
Perhatian saat menggunakan
from os.path import split
Inspirasi dari
sumber
Nilai Posting Ini
Maksud saya adalah menawarkan solusi non regex yang dapat diterapkan secara umum.
Saya akan membuat tiga fungsi:
find_first_digit
yang saya pinjam dari @AnuragUniyal . Ini akan menemukan posisi digit pertama atau non-digit dalam sebuah string.split_digits
yang merupakan generator yang mengambil string menjadi potongan digit dan non digit. Ini juga akanyield
bilangan bulat ketika angka.natural_key
hanya membungkussplit_digits
menjadituple
. Ini adalah apa yang kita gunakan sebagai kunci untuksorted
,max
,min
.Fungsi
Kita dapat melihat bahwa itu adalah umum bahwa kita dapat memiliki beberapa digit potongan:
Atau biarkan sensitif huruf:
Kita dapat melihat bahwa ia mengurutkan daftar OP dalam urutan yang sesuai
Tetapi ia dapat menangani daftar yang lebih rumit juga:
Setara dengan regex saya adalah
sumber
Salah satu opsi adalah mengubah string menjadi tuple dan mengganti digit menggunakan form diperluas http://wiki.answers.com/Q/What_does_expanded_form_mean
dengan cara itu a90 akan menjadi ("a", 90,0) dan a1 akan menjadi ("a", 1)
di bawah ini adalah beberapa kode sampel (yang tidak terlalu efisien karena cara ini menghilangkan 0 dari angka-angka terkemuka)
keluaran:
sumber
('b', 1) < ('b', 'e', 't', 'a', 1, '.', 1)
akan kembaliTypeError: unorderable types: int() < str()
natsort
, pypi.org/project/natsortBerdasarkan jawaban di sini, saya menulis
natural_sorted
fungsi yang berperilaku seperti fungsi bawaansorted
:Kode sumber juga tersedia di repositori cuplikan GitHub saya: https://github.com/bdrung/snippets/blob/master/natural_sorted.py
sumber
Jawaban di atas baik untuk contoh spesifik yang ditunjukkan, tetapi kehilangan beberapa kasus berguna untuk pertanyaan yang lebih umum tentang jenis alami. Saya hanya mendapat sedikit dari salah satu kasus itu, jadi menciptakan solusi yang lebih menyeluruh:
Kode uji dan beberapa tautan (mematikan dan menghidupkan StackOverflow) ada di sini: http://productarchitect.com/code/better-natural-sort.py
Umpan balik. Itu tidak dimaksudkan untuk menjadi solusi yang pasti; hanya selangkah ke depan.
sumber
natsorted
danhumansorted
gagal karena salah digunakan ... Anda mencoba meneruskannatsorted
sebagai kunci tetapi sebenarnya fungsi penyortiran itu sendiri. Anda harus mencobanatsort_keygen()
.Kemungkinan besar
functools.cmp_to_key()
terkait erat dengan implementasi yang mendasari jenis python. Selain itu, parameter cmp adalah lawas. Cara modern adalah mengubah item input menjadi objek yang mendukung operasi perbandingan kaya yang diinginkan.Di bawah CPython 2.x, objek dengan tipe yang berbeda dapat dipesan bahkan jika masing-masing operator pembanding yang kaya belum diterapkan. Di bawah CPython 3.x, objek dari tipe yang berbeda harus secara eksplisit mendukung perbandingan. Lihat Bagaimana Python membandingkan string dan int? yang menghubungkan ke dokumentasi resmi . Sebagian besar jawaban tergantung pada pemesanan tersirat ini. Beralih ke Python 3.x akan membutuhkan tipe baru untuk mengimplementasikan dan menyatukan perbandingan antara angka dan string.
Ada tiga pendekatan berbeda. Yang pertama menggunakan kelas bersarang untuk mengambil keuntungan dari
Iterable
algoritma perbandingan Python . Yang kedua membuka gulungan sarang ini ke dalam satu kelas. Foregoes forcloes ketiga subclassingstr
untuk fokus pada kinerja. Semua diatur waktunya; yang kedua dua kali lebih cepat sedangkan yang ketiga hampir enam kali lebih cepat. Subclassingstr
tidak diperlukan, dan mungkin ide yang buruk sejak awal, tetapi memang disertai dengan kenyamanan tertentu.Sortir karakter digandakan untuk memaksa pemesanan berdasarkan kasus, dan bertukar kasus untuk memaksa huruf kecil untuk mengurutkan terlebih dahulu; ini adalah definisi khas "jenis alami". Saya tidak bisa memutuskan jenis pengelompokan; beberapa mungkin lebih suka yang berikut ini, yang juga membawa manfaat kinerja yang signifikan:
Jika digunakan, operator pembanding diatur
object
agar tidak diabaikan olehfunctools.total_ordering
operator .Penyortiran alami cukup rumit dan samar-samar didefinisikan sebagai masalah. Jangan lupa untuk menjalankan
unicodedata.normalize(...)
terlebih dahulu, dan mempertimbangkan penggunaanstr.casefold()
daripadastr.lower()
. Mungkin ada masalah penyandian halus yang belum saya pertimbangkan. Jadi saya sementara merekomendasikan perpustakaan natsort . Aku melirik sekilas repositori github; pemeliharaan kode telah menjadi bintang.Semua algoritme yang saya lihat bergantung pada trik seperti menggandakan dan menurunkan karakter, dan mengganti huruf besar-kecil. Meskipun ini menggandakan waktu berjalan, sebuah alternatif akan membutuhkan pemesanan alami total pada set karakter input. Saya tidak berpikir ini adalah bagian dari spesifikasi unicode, dan karena ada lebih banyak digit unicode daripada itu
[0-9]
, membuat penyortiran seperti itu akan sama menakutkannya. Jika Anda ingin perbandingan sadar-lokal, siapkan string Anda denganlocale.strxfrm
per Penyortiran Python CARA .sumber
Izinkan saya mengirimkan pendapat saya sendiri tentang kebutuhan ini:
Sekarang jika kita memiliki daftar seperti ini:
Kita cukup menggunakan
key=
kwarg untuk melakukan pengurutan alami:Kelemahan di sini tentu saja, seperti sekarang, fungsinya akan mengurutkan huruf besar sebelum huruf kecil.
Saya akan menyerahkan implementasi dari case-insenstive grouper kepada pembaca :-)
sumber
Saya sarankan Anda cukup menggunakan
key
argumen kata kuncisorted
untuk mencapai daftar yang Anda inginkanMisalnya:
sumber
a_51
akan menjadi setelaha500
, meskipun 500> 51Mengikuti jawaban @Mark Byers, berikut adalah adaptasi yang menerima
key
parameter, dan lebih sesuai dengan PEP8.Saya juga membuat Intisari
sumber
key
parameternya? Tapi ini juga dicontohkan dalam jawaban @ beauburrierPeningkatan pada perbaikan Claudiu pada jawaban Mark Byer ;-)
BTW, mungkin tidak semua orang ingat bahwa argumen fungsi dievaluasi pada
def
waktunyasumber
Ucapan Terima Kasih :
Pekerjaan Rumah Sortir Bubble
Cara membaca string satu huruf setiap kali dalam python
sumber
sumber