Adakah yang punya sumber daya yang bagus atau memberikan contoh jenis urutan alami dalam C # untuk sebuah FileInfo
array? Saya mengimplementasikan IComparer
antarmuka dalam jenis saya.
sumber
Adakah yang punya sumber daya yang bagus atau memberikan contoh jenis urutan alami dalam C # untuk sebuah FileInfo
array? Saya mengimplementasikan IComparer
antarmuka dalam jenis saya.
Hal termudah untuk dilakukan adalah hanya P / Aktifkan fungsi bawaan di Windows, dan gunakan sebagai fungsi perbandingan di IComparer
:
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern int StrCmpLogicalW(string psz1, string psz2);
Michael Kaplan memiliki beberapa contoh tentang bagaimana fungsi ini bekerja di sini , dan perubahan yang dibuat untuk Vista agar berfungsi lebih intuitif. Sisi positif dari fungsi ini adalah ia akan memiliki perilaku yang sama dengan versi Windows yang dijalankannya, namun ini berarti bahwa ia berbeda antara versi Windows sehingga Anda perlu mempertimbangkan apakah ini masalah bagi Anda.
Jadi implementasi yang lengkap akan menjadi seperti:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
public sealed class NaturalStringComparer : IComparer<string>
{
public int Compare(string a, string b)
{
return SafeNativeMethods.StrCmpLogicalW(a, b);
}
}
public sealed class NaturalFileInfoNameComparer : IComparer<FileInfo>
{
public int Compare(FileInfo a, FileInfo b)
{
return SafeNativeMethods.StrCmpLogicalW(a.Name, b.Name);
}
}
Comparer<T>
alih-alih mengimplementasikanIComparer<T>
, Anda mendapatkan implementasi bawaan dariIComparer
antarmuka (non-generik) yang memanggil metode generik Anda, untuk digunakan dalam API yang menggunakannya. Ini pada dasarnya gratis untuk dilakukan juga: cukup hapus "I" dan ubahpublic int Compare(...)
kepublic override int Compare(...)
. Sama untukIEqualityComparer<T>
danEqualityComparer<T>
.Hanya berpikir saya akan menambahkan ini (dengan solusi paling ringkas yang bisa saya temukan):
Di atas bantalan nomor dalam string dengan panjang maksimal semua angka di semua string dan menggunakan string yang dihasilkan untuk mengurutkan.
Pemain ke (
int?
) adalah untuk memungkinkan koleksi string tanpa nomor (.Max()
pada lemparan enumerable kosong aInvalidOperationException
).sumber
.DefaultIfEmpty().Max()
alih-alih melakukan castingint?
. Juga patut dilakukansource.ToList()
untuk menghindari penghitungan ulang enumerable.Tak satu pun dari implementasi yang ada tampak hebat jadi saya menulis sendiri. Hasilnya hampir identik dengan pengurutan yang digunakan oleh versi modern Windows Explorer (Windows 7/8). Satu-satunya perbedaan yang pernah saya lihat adalah 1) walaupun Windows dulu (misalnya XP) menangani angka berapa pun, sekarang dibatasi hingga 19 digit - milik saya tidak terbatas, 2) Windows memberikan hasil yang tidak konsisten dengan set angka Unicode tertentu - karya tambang baik (walaupun secara numerik tidak membandingkan angka dari pasangan pengganti; Windows juga tidak), dan 3) milik saya tidak dapat membedakan berbagai jenis bobot sortir non-primer jika terjadi dalam bagian yang berbeda (mis. "e-1é" vs " é1e- "- bagian sebelum dan sesudah nomor memiliki perbedaan berat diakritik dan tanda baca).
Tanda tangan cocok dengan
Comparison<string>
delegasi:Ini kelas wrapper untuk digunakan sebagai
IComparer<string>
:Contoh:
Berikut seperangkat nama file yang saya gunakan untuk pengujian:
sumber
Solusi C # murni untuk linq orderby:
http://zootfroot.blogspot.com/2009/09/natural-sort-compare-with-linq-orderby.html
sumber
Jawaban Matthews Horsley adalah metode tercepat yang tidak mengubah perilaku tergantung pada versi windows mana program Anda berjalan. Namun, itu bisa lebih cepat dengan membuat regex sekali, dan menggunakan RegexOptions.Compiled. Saya juga menambahkan opsi untuk memasukkan pembanding string sehingga Anda dapat mengabaikan case jika diperlukan, dan sedikit meningkatkan keterbacaan.
Digunakan oleh
Ini membutuhkan 450ms untuk mengurutkan 100.000 string dibandingkan 300ms untuk perbandingan .net string default - cukup cepat!
sumber
Solusi saya:
Hasil:
sumber
Anda perlu berhati-hati - saya samar-samar ingat pernah membaca bahwa StrCmpLogicalW, atau sesuatu seperti itu, tidak sepenuhnya transitif, dan saya telah mengamati. Metode semacam NET untuk kadang-kadang terjebak dalam loop tak terbatas jika fungsi perbandingan melanggar aturan itu.
Perbandingan transitif akan selalu melaporkan bahwa <c jika a <b dan b <c. Ada fungsi yang melakukan perbandingan urutan jenis alami yang tidak selalu memenuhi kriteria itu, tapi saya tidak ingat apakah itu StrCmpLogicalW atau yang lainnya.
sumber
CultureInfo
memiliki propertiCompareInfo
, dan objek yang dikembalikannya dapat memberi AndaSortKey
objek. Ini, pada gilirannya, dapat dibandingkan dan menjamin transitivitas.Ini adalah kode saya untuk mengurutkan string yang memiliki karakter alfa dan numerik.
Pertama, metode ekstensi ini:
Kemudian, cukup gunakan di mana saja dalam kode Anda seperti ini:
Bagaimana cara kerjanya ? Dengan mengganti dengan nol:
Bekerja dengan nomor kelipatan:
Semoga itu bisa membantu.
sumber
Menambahkan ke jawaban Greg Beech (karena saya baru saja mencari itu), jika Anda ingin menggunakan ini dari Linq Anda dapat menggunakan
OrderBy
yang membutuhkanIComparer
. Misalnya:sumber
Berikut adalah contoh yang relatif sederhana yang tidak menggunakan P / Invoke dan menghindari alokasi apa pun selama eksekusi.
Itu tidak mengabaikan nol terkemuka, jadi
01
datang setelah2
.Tes unit terkait:
sumber
Saya sebenarnya telah mengimplementasikannya sebagai metode ekstensi
StringComparer
agar Anda dapat melakukannya misalnya:StringComparer.CurrentCulture.WithNaturalSort()
atauStringComparer.OrdinalIgnoreCase.WithNaturalSort()
.Dihasilkan tersebut
IComparer<string>
dapat digunakan di semua tempat sepertiOrderBy
,OrderByDescending
,ThenBy
,ThenByDescending
,SortedSet<string>
, dll Dan Anda dapat sensitivitas kasus masih mudah Tweak, budaya, dllImplementasinya cukup sepele dan harus berkinerja cukup baik bahkan pada urutan besar.
Saya juga menerbitkannya sebagai paket NuGet kecil , jadi Anda bisa melakukannya:
Kode termasuk komentar dokumentasi XML dan paket tes tersedia di repositori NaturalSort.Extension GitHub .
Seluruh kode adalah ini (jika Anda belum dapat menggunakan C # 7, cukup instal paket NuGet):
sumber
Berikut ini adalah cara LINQ satu garis regex-less naif (dipinjam dari python):
sumber
Dump()
. Terima kasih telah menunjukkan.Memperluas pada beberapa jawaban sebelumnya dan menggunakan metode ekstensi, saya datang dengan yang berikut ini tidak memiliki peringatan potensi enumerasi enumerable ganda, atau masalah kinerja yang berkaitan dengan menggunakan beberapa objek regex, atau memanggil regex tidak perlu, yang dikatakan, ia menggunakan ToList (), yang dapat meniadakan manfaat dalam koleksi yang lebih besar.
Selector mendukung pengetikan generik untuk memungkinkan delegasi ditugaskan, elemen-elemen dalam kumpulan sumber dimutasi oleh pemilih, kemudian dikonversi ke string dengan ToString ().
sumber
Terinspirasi oleh solusi Michael Parker, berikut ini adalah
IComparer
implementasi yang bisa Anda gunakan di salah satu metode pemesanan LINQ:sumber
Kami memiliki kebutuhan untuk jenis alami untuk berurusan dengan teks dengan pola berikut:
Untuk beberapa alasan ketika saya pertama kali melihat SO, saya tidak menemukan posting ini dan mengimplementasikan posting kami sendiri. Dibandingkan dengan beberapa solusi yang disajikan di sini, sementara dalam konsep yang serupa, itu bisa memiliki manfaat yang lebih sederhana dan lebih mudah dipahami. Namun, sementara saya mencoba untuk melihat hambatan kinerja, ini masih jauh lebih lambat daripada implementasi standar
OrderBy()
.Berikut adalah metode ekstensi yang saya terapkan:
Idenya adalah untuk membagi string asli menjadi blok digit dan non-digit (
"\d+|\D+"
). Karena ini adalah tugas yang berpotensi mahal, itu dilakukan hanya sekali per entri. Kami kemudian menggunakan pembanding objek yang sebanding (maaf, saya tidak dapat menemukan cara yang lebih tepat untuk mengatakannya). Ini membandingkan setiap blok dengan blok yang sesuai di string lain.Saya ingin umpan balik tentang bagaimana ini bisa diperbaiki dan apa kelemahan utamanya. Perhatikan bahwa pemeliharaan adalah penting bagi kami pada saat ini dan kami saat ini tidak menggunakannya dalam kumpulan data yang sangat besar.
sumber
Versi yang lebih mudah dibaca / dipelihara.
sumber
Biarkan saya menjelaskan masalah saya dan bagaimana saya bisa menyelesaikannya.
Masalah: - Mengurutkan file berdasarkan FileName dari objek FileInfo yang diambil dari Direktori.
Solusi: - Saya memilih nama file dari FileInfo dan memotong bagian ".png" dari nama file. Sekarang, lakukan saja List.Sort (), yang mengurutkan nama file dalam urutan penyortiran alami. Berdasarkan pengujian saya, saya menemukan bahwa .png mengacaukan urutan penyortiran. Lihatlah kode di bawah ini
sumber