private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Katakanlah saya ingin mengulanginya dan menulis sesuatu seperti memproses #n dari #m.
Apakah ada cara saya bisa mengetahui nilai m tanpa iterasi sebelum iterasi utama saya?
Saya harap saya membuat diri saya jelas.
c#
.net
ienumerable
sebagomez
sumber
sumber
The
System.Linq.Enumerable.Count
metode penyuluhanIEnumerable<T>
memiliki pelaksanaan berikut:Jadi ia mencoba untuk menggunakan
ICollection<T>
, yang memilikiCount
properti, dan menggunakannya jika memungkinkan. Kalau tidak, iterates.Jadi taruhan terbaik Anda adalah menggunakan
Count()
metode ekstensi padaIEnumerable<T>
objek Anda , karena Anda akan mendapatkan kinerja terbaik dengan cara itu.sumber
ICollection<T>
pertama.T
padaIEnumerator<T> enumerator = source.GetEnumerator()
, hanya Anda dapat melakukan ini:IEnumerator enumerator = source.GetEnumerator()
dan harus bekerja!IEnumerable<T>
mewarisiIDisposable
yang memungkinkanusing
pernyataan untuk membuangnya secara otomatis.IEnumerable
tidak. Jadi, jika Anda meneleponGetEnumerator
dengan cara apa pun, Anda harus menyelesaikannya denganvar d = e as IDisposable; if (d != null) d.Dispose();
Cukup tambahkan beberapa info tambahan:
The
Count()
ekstensi tidak selalu iterate. Pertimbangkan Linq ke Sql, tempat penghitungan menuju database, tetapi alih-alih mengembalikan semua baris, ia mengeluarkanCount()
perintah Sql dan mengembalikan hasilnya.Selain itu, kompiler (atau runtime) cukup pintar sehingga akan memanggil
Count()
metode objek jika memilikinya. Jadi tidak seperti yang dikatakan responden lain, benar-benar bodoh dan selalu berulang untuk menghitung elemen.Dalam banyak kasus di mana programmer hanya memeriksa
if( enumerable.Count != 0 )
menggunakanAny()
metode ekstensi, karenaif( enumerable.Any() )
jauh lebih efisien dengan evaluasi malas linq karena dapat mengalami hubungan pendek setelah dapat menentukan ada elemen. Ini juga lebih mudah dibacasumber
.Count
properti karena selalu tahu ukurannya. Saat memintacollection.Count
tidak ada perhitungan tambahan, itu hanya mengembalikan jumlah yang sudah diketahui. SamaArray.length
seperti yang saya tahu. Namun,.Any()
dapatkan enumerator dari sumber menggunakanusing (IEnumerator<TSource> enumerator = source.GetEnumerator())
dan mengembalikan true jika itu bisa dilakukanenumerator.MoveNext()
. Untuk koleksiif(collection.Count > 0)
:, array:if(array.length > 0)
dan lakukan enumerablesif(collection.Any())
.IQueryably<T>
memasukkan Anda ke aIEnumerable<T>
itu tidak akan mengeluarkan jumlah sql. Ketika saya menulis ini, Linq to Sql masih baru; Saya pikir saya hanya mendorong untuk menggunakanAny()
karena untuk enumerables, koleksi dan sql itu jauh lebih efisien dan mudah dibaca (secara umum). Terima kasih telah meningkatkan jawabannya.Seorang teman saya memiliki serangkaian posting blog yang memberikan ilustrasi mengapa Anda tidak bisa melakukan ini. Dia menciptakan fungsi yang mengembalikan IEnumerable di mana setiap iterasi mengembalikan bilangan prima berikutnya, sampai ke sana
ulong.MaxValue
, dan item berikutnya tidak dihitung sampai Anda memintanya. Cepat, pertanyaan pop: berapa banyak barang yang dikembalikan?Ini postingannya, tapi agak panjang:
sumber
EnumerableFeatures
objek) tidak akan memerlukan enumerator untuk melakukan sesuatu yang sulit, tetapi mampu mengajukan pertanyaan seperti itu (bersama dengan beberapa yang lain seperti "Bisakah Anda berjanji untuk selalu mengembalikan urutan item yang sama "," Bisakah Anda dengan aman terpapar kode yang seharusnya tidak mengubah koleksi dasar Anda ", dll.) akan sangat berguna.set yield options
pernyataan atau sesuatu yang serupa untuk mendukungnya. Jika dirancang dengan benar, sebuahIEnhancedEnumerator
dapat membuat hal-hal seperti LINQ jauh lebih bermanfaat dengan menghilangkan banyak "pertahanan"ToArray
atauToList
panggilan, terutama ...Enumerable.Concat
digunakan untuk menggabungkan koleksi besar yang tahu banyak tentang dirinya dengan yang kecil yang tidak.IEnumerable tidak dapat dihitung tanpa iterasi.
Dalam keadaan "normal", dimungkinkan untuk kelas yang mengimplementasikan IEnumerable atau IEnumerable <T>, seperti List <T>, untuk mengimplementasikan metode Count dengan mengembalikan properti Daftar <T> .Count. Namun, metode Count sebenarnya bukan metode yang didefinisikan pada antarmuka IEnumerable <T> atau IEnumerable. (Satu-satunya yang, pada kenyataannya, adalah GetEnumerator.) Dan ini berarti bahwa implementasi khusus kelas tidak dapat disediakan untuk itu.
Sebaliknya, Hitung itu adalah metode ekstensi, didefinisikan pada kelas statis Enumerable. Ini berarti dapat dipanggil pada instance kelas turunan <n> IEnumerable, terlepas dari implementasi kelas itu. Tetapi itu juga berarti itu diterapkan di satu tempat, di luar kelas-kelas tersebut. Yang tentu saja berarti bahwa itu harus diimplementasikan dengan cara yang sepenuhnya independen dari internal kelas ini. Satu-satunya cara untuk melakukan penghitungan adalah melalui iterasi.
sumber
Atau Anda dapat melakukan hal berikut:
sumber
Tidak, tidak secara umum. Satu poin dalam menggunakan enumerables adalah bahwa set sebenarnya objek dalam enumerasi tidak diketahui (sebelumnya, atau bahkan sama sekali).
sumber
Anda dapat menggunakan System.Linq.
Anda akan mendapatkan hasil '2'.
sumber
Melampaui pertanyaan langsung Anda (yang telah dijawab sepenuhnya dalam negatif), jika Anda ingin melaporkan kemajuan sambil memproses enumerable, Anda mungkin ingin melihat posting blog saya Kemajuan Pelaporan Selama Pertanyaan Linq .
Ini memungkinkan Anda melakukan ini:
sumber
Saya menggunakan cara seperti di dalam sebuah metode untuk memeriksa disahkan pada
IEnumberable
kontenDi dalam metode seperti ini:
sumber
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.Tergantung pada versi .Net dan implementasi objek IEnumerable Anda. Microsoft telah memperbaiki metode IEnumerable.Count untuk memeriksa implementasi, dan menggunakan ICollection.Count atau ICollection <TSource> .Count, lihat detailnya di sini https://connect.microsoft.com/VisualStudio/feedback/details/454130
Dan di bawah ini adalah MSIL dari Ildasm untuk System.Core, di mana System.Linq berada.
sumber
Berikut ini adalah diskusi yang bagus tentang evaluasi malas dan eksekusi yang ditangguhkan . Pada dasarnya Anda harus mematerialisasikan daftar untuk mendapatkan nilai itu.
sumber
Hasil dari fungsi IEnumerable.Count () mungkin salah. Ini adalah sampel yang sangat sederhana untuk diuji:
Hasil harus (7,7,3,3) tetapi hasil aktualnya adalah (7,7,3,17)
sumber
Cara terbaik yang saya temukan adalah menghitung dengan mengubahnya menjadi daftar.
sumber
Saya sarankan memanggil ToList. Ya, Anda melakukan enumerasi lebih awal, tetapi Anda masih memiliki akses ke daftar item Anda.
sumber
Ini mungkin tidak menghasilkan kinerja terbaik, tetapi Anda dapat menggunakan LINQ untuk menghitung elemen dalam IEnumerable:
sumber
Saya pikir cara termudah untuk melakukan ini
Referensi: system.linq.enumerable
sumber
Saya menggunakan
IEnum<string>.ToArray<string>().Length
dan berfungsi dengan baik.sumber
IEnum<string>.Count();
"?Saya menggunakan kode seperti itu, jika saya memiliki daftar string:
sumber