Apa cara "terbaik" (dengan mempertimbangkan kecepatan dan keterbacaan) untuk menentukan apakah sebuah daftar kosong? Meskipun daftarnya berjenis IEnumerable<T>
dan tidak memiliki properti Hitungan.
Saat ini saya sedang memikirkan di antara ini:
if (myList.Count() == 0) { ... }
dan ini:
if (!myList.Any()) { ... }
Dugaan saya adalah bahwa opsi kedua lebih cepat, karena akan kembali dengan hasil segera setelah melihat item pertama, sedangkan opsi kedua (untuk IEnumerable) perlu mengunjungi setiap item untuk mengembalikan hitungan.
Karena itu, apakah opsi kedua terlihat dapat dibaca oleh Anda? Mana yang lebih kamu sukai? Atau dapatkah Anda memikirkan cara yang lebih baik untuk menguji daftar kosong?
Respons edit @ lassevk tampaknya yang paling logis, ditambah dengan sedikit pemeriksaan waktu proses untuk menggunakan jumlah cache jika memungkinkan, seperti ini:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
dancast
tapi gunakanas
dannull
periksa:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
setara denganlist.IsEmpty
? Metode kerangka kerja harus dioptimalkan - ada baiknya menulis yang baru hanya jika Anda mengetahuinya sebagai penghambat kinerja.IsEmpty
metode ekstensi. github.com/dotnet/corefx/issues/35054 Silakan centang dan pilih jika Anda suka dan setuju.Jawaban:
Anda bisa melakukan ini:
Edit : Perhatikan bahwa hanya menggunakan metode .Count akan cepat jika sumber yang mendasarinya sebenarnya memiliki properti Hitungan cepat. Pengoptimalan yang valid di atas adalah dengan mendeteksi beberapa jenis dasar dan cukup menggunakan properti .Count dari keduanya, bukan pendekatan .Any (), tetapi kemudian kembali ke .Any () jika tidak ada jaminan yang dapat dibuat.
sumber
IsNullOrEmpty()
.return !source?.Any() ?? true;
Saya akan membuat satu tambahan kecil untuk kode yang tampaknya telah Anda selesaikan: periksa juga
ICollection
, karena ini diterapkan bahkan oleh beberapa kelas generik yang tidak usang juga (yaitu,Queue<T>
danStack<T>
). Saya juga akan menggunakanas
alih-alihis
karena itu lebih idiomatis dan telah terbukti lebih cepat .sumber
NotSupportedException
atauNotImplementedException
. Saya pertama kali menggunakan contoh kode Anda ketika saya menemukan koleksi yang saya gunakan membuat pengecualian untuk Count (siapa yang tahu ...).Apakah ini mengejutkan Anda? Saya membayangkan bahwa untuk
IList
implementasi,Count
cukup membaca jumlah elemen secara langsung sementaraAny
harus menanyakanIEnumerable.GetEnumerator
metode, membuat instance dan memanggilMoveNext
setidaknya sekali./ EDIT @Matt:
Ya, tentu saja. Ini yang saya maksud. Sebenarnya, ini menggunakan
ICollection
alih-alihIList
tetapi hasilnya sama.sumber
Saya baru saja menulis tes singkat, coba ini:
Yang kedua hampir tiga kali lebih lambat :)
Mencoba uji stopwatch lagi dengan Stack atau array atau skenario lain, itu benar-benar tergantung pada jenis daftar yang terlihat - karena mereka membuktikan Hitungan lebih lambat.
Jadi saya kira itu tergantung pada jenis daftar yang Anda gunakan!
(Sekadar menunjukkan, saya memasukkan 2000+ objek dalam Daftar dan menghitung masih lebih cepat, berlawanan dengan jenis lainnya)
sumber
Enumerable.Count<T>()
memiliki penanganan khusus untukICollection<T>
. Jika Anda mencoba ini dengan sesuatu yang lain dari daftar dasar, saya berharap Anda akan melihat secara signifikan berbeda (lebih lambat) hasil.Any()
akan tetap sama.Enumerable.Any<T>()
forICollection<T>
? tentunya parameterlessAny()
bisa memeriksaCount
propertiICollection<T>
juga?List.Count
adalah O (1) menurut dokumentasi Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
jadi gunakan saja
List.Count == 0
saja jauh lebih cepat daripada kueriIni karena ia memiliki anggota data yang disebut Hitungan yang diperbarui setiap kali ada sesuatu yang ditambahkan atau dihapus dari daftar, jadi ketika Anda memanggilnya
List.Count
tidak harus mengulang melalui setiap elemen untuk mendapatkannya, ia hanya mengembalikan anggota data.sumber
Opsi kedua jauh lebih cepat jika Anda memiliki banyak item.
Any()
kembali segera setelah 1 item ditemukan.Count()
harus terus menelusuri seluruh daftar.Misalkan pencacahan memiliki 1000 item.
Any()
akan memeriksa yang pertama, lalu mengembalikan true.Count()
akan mengembalikan 1000 setelah melewati seluruh pencacahan.Ini berpotensi lebih buruk jika Anda menggunakan salah satu dari predicate overrides - Count () masih harus memeriksa setiap item, meskipun hanya ada satu yang cocok.
Anda terbiasa menggunakan Apa saja - ini masuk akal dan dapat dibaca.
Satu peringatan - jika Anda memiliki Daftar, bukan hanya IEnumerable, gunakan properti Hitung daftar itu.
sumber
@Konrad yang mengejutkan saya adalah bahwa dalam pengujian saya, saya meneruskan daftar ke metode yang menerima
IEnumerable<T>
, sehingga runtime tidak dapat mengoptimalkannya dengan memanggil metode ekstensi Count () untukIList<T>
.Saya hanya dapat berasumsi bahwa metode ekstensi Count () untuk IEnumerable melakukan sesuatu seperti ini:
... dengan kata lain, sedikit pengoptimalan waktu proses untuk kasus khusus
IList<T>
./ EDIT @Konrad +1 sobat - Anda benar tentang hal itu kemungkinan besar ada di
ICollection<T>
.sumber
Oke, jadi bagaimana dengan yang ini?
EDIT: Saya baru saja menyadari bahwa seseorang telah membuat sketsa solusi ini. Telah disebutkan bahwa metode Any () akan melakukan ini, tetapi mengapa tidak melakukannya sendiri? Salam
sumber
using
blok karena jika tidak, Anda telah membangun sebuahIDisposable
objek dan kemudian meninggalkannya. Kemudian, tentu saja, ini menjadi lebih ringkas ketika Anda menggunakan metode ekstensi yang sudah ada dan hanya mengubahnya menjadireturn !enumerable.Any()
(yang melakukan hal ini dengan tepat).Any()
melakukan persis seperti itu, jadi menambahkan metode yang persis sama dengan nama lain hanya akan membingungkan.Ide lain:
Namun saya lebih suka pendekatan Any ().
sumber
Ini sangat penting agar ini berfungsi dengan Entity Framework:
sumber
Jika saya memeriksa dengan Count () Linq mengeksekusi "SELECT COUNT (*) .." dalam database, tetapi saya perlu memeriksa apakah hasilnya berisi data, saya memutuskan untuk memperkenalkan FirstOrDefault () daripada Count ();
Sebelum
Setelah
sumber
sumber
Inilah implementasi saya atas jawaban Dan Tao, memungkinkan untuk sebuah predikat:
sumber
sumber
myList.ToList().Count == 0
. Itu sajasumber
Metode ekstensi ini berfungsi untuk saya:
sumber