private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Powiedzmy, że chcę je powtórzyć i napisz coś takiego jak przetwarzanie #n z #m.
Czy istnieje sposób, aby dowiedzieć się o wartości m bez iteracji przed moją główną iteracją?
Mam nadzieję, że wyraziłem się jasno.
c#
.net
ienumerable
sebagomez
źródło
źródło
Metoda
System.Linq.Enumerable.Count
rozszerzeniaIEnumerable<T>
ma następującą implementację:Próbuje więc przesyłać do
ICollection<T>
, który maCount
właściwość, i używa go, jeśli to możliwe. W przeciwnym razie iteruje.Więc najlepszym rozwiązaniem jest użycie
Count()
metody rozszerzenia naIEnumerable<T>
obiekcie, ponieważ uzyskasz w ten sposób najlepszą możliwą wydajność.źródło
ICollection<T>
najpierw.T
włączonego rodzaju ogólnegoIEnumerator<T> enumerator = source.GetEnumerator()
, po prostu możesz to zrobić:IEnumerator enumerator = source.GetEnumerator()
i powinien działać!IEnumerable<T>
dziedziczy,IDisposable
co pozwalausing
instrukcji na automatyczne usunięcie.IEnumerable
nie. Więc jeśli zadzwonisz wGetEnumerator
którąkolwiek stronę, powinieneś skończyć zvar d = e as IDisposable; if (d != null) d.Dispose();
Dodając dodatkowe informacje:
Count()
Rozbudowa nie zawsze iteracji. Rozważ Linq do Sql, gdzie liczba trafia do bazy danych, ale zamiast przywracać wszystkie wiersze, wydajeCount()
polecenie Sql i zwraca ten wynik.Ponadto kompilator (lub środowisko wykonawcze) jest na tyle inteligentny, że wywoła
Count()
metodę object , jeśli ją posiada. Więc nie jest tak, jak mówią inni respondenci, będąc całkowicie ignorantem i zawsze iterując, aby policzyć elementy.W wielu przypadkach, gdy programista sprawdza po prostu
if( enumerable.Count != 0 )
za pomocąAny()
metody rozszerzenia, ponieważif( enumerable.Any() )
jest to o wiele bardziej wydajne z leniwą oceną linq, ponieważ może zwierać, gdy może stwierdzić, że są jakieś elementy. Jest także bardziej czytelnyźródło
.Count
właściwości, ponieważ zawsze wie, że ma rozmiar. Podczas zapytaniacollection.Count
nie ma dodatkowych obliczeń, po prostu zwraca on już znaną liczbę. To samo oArray.length
ile wiem. Jednak.Any()
pobiera moduł wyliczający źródłausing (IEnumerator<TSource> enumerator = source.GetEnumerator())
i zwraca true, jeśli to możliweenumerator.MoveNext()
. W przypadku kolekcjiif(collection.Count > 0)
:, tablice:if(array.length > 0)
i na wyliczeniachif(collection.Any())
.IQueryably<T>
naIEnumerable<T>
nie, nie będzie wystawiać liczby sql. Kiedy to napisałem, Linq do Sql był nowy; Myślę, że po prostu naciskałem na użycie,Any()
ponieważ dla wyliczeń, kolekcji i sql było znacznie bardziej wydajne i czytelne (ogólnie). Dzięki za poprawę odpowiedzi.Mój przyjaciel ma serię postów na blogu, które ilustrują, dlaczego nie możesz tego zrobić. Tworzy funkcję, która zwraca IEnumerable, gdzie każda iteracja zwraca następną liczbę pierwszą, aż do
ulong.MaxValue
, a następny element nie jest obliczany, dopóki go nie poprosisz. Szybkie, popowe pytanie: ile przedmiotów jest zwracanych?Oto posty, ale są one dość długie:
źródło
EnumerableFeatures
obiekt) nie wymagałoby od liczących robienia czegokolwiek trudnego, ale możliwość zadawania takich pytań (wraz z innymi, takimi jak „Czy możesz obiecać zawsze zwracaj tę samą sekwencję elementów ”,„ Czy możesz być narażony na kod, który nie powinien zmieniać twojej podstawowej kolekcji ”itp.) byłby bardzo przydatny.set yield options
instrukcję lub coś podobnego do jej obsługi. Jeśli jest odpowiednio zaprojektowany,IEnhancedEnumerator
może sprawić, że LINQ będzie znacznie bardziej użyteczny, eliminując wiele „defensywnych”ToArray
lubToList
połączeń, szczególnie ...Enumerable.Concat
są używane do łączenia dużej kolekcji, która dużo o sobie wie, z małą, która nie wie.IEnumerable nie może się liczyć bez iteracji.
W „normalnych” okolicznościach klasy implementujące IEnumerable lub IEnumerable <T>, takie jak List <T>, mogłyby zaimplementować metodę Count, zwracając właściwość List <T> .Count. Jednak metoda Count nie jest w rzeczywistości metodą zdefiniowaną w interfejsie IEnumerable <T> lub IEnumerable. (Jedynym, który w rzeczywistości jest GetEnumerator). A to oznacza, że nie można zapewnić dla niego implementacji specyficznej dla klasy.
Raczej licz, to metoda rozszerzenia zdefiniowana w klasie statycznej Enumerable. Oznacza to, że można go wywołać w dowolnej instancji klasy pochodnej <T> IEnumerable, niezależnie od implementacji tej klasy. Ale oznacza to również, że jest implementowany w jednym miejscu, zewnętrznym względem którejkolwiek z tych klas. Co oczywiście oznacza, że musi zostać zaimplementowany w sposób całkowicie niezależny od wewnętrznych elementów tej klasy. Jedynym takim sposobem liczenia jest iteracja.
źródło
Alternatywnie możesz wykonać następujące czynności:
źródło
Nie, ogólnie nie. Jednym z punktów przy użyciu wyliczeń jest to, że rzeczywisty zestaw obiektów w wyliczeniu nie jest znany (wcześniej, a nawet wcale).
źródło
Możesz użyć System.Linq.
Otrzymasz wynik „2”.
źródło
Wykraczając poza twoje bezpośrednie pytanie (na które dokładnie udzielono odpowiedzi przeczącej), jeśli chcesz zgłosić postęp podczas przetwarzania wyliczenia, możesz spojrzeć na mój post na blogu Zgłaszanie postępów podczas zapytań Linq .
Pozwala ci to zrobić:
źródło
Kiedyś taki sposób wewnątrz metody, by sprawdzić przekazany w
IEnumberable
treściWewnątrz metody takiej jak ta:
źródło
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.To zależy od wersji .Net i implementacji Twojego obiektu IEnumerable. Microsoft naprawił metodę IEnumerable.Count w celu sprawdzenia implementacji i używa ICollection.Count lub ICollection <TSource> .Count, zobacz szczegóły tutaj https://connect.microsoft.com/VisualStudio/feedback/details/454130
A poniżej znajduje się MSIL z Ildasm dla System.Core, w którym rezyduje System.Linq.
źródło
Oto świetna dyskusja na temat leniwej oceny i odroczenia wykonania . Zasadniczo musisz zmaterializować listę, aby uzyskać tę wartość.
źródło
Wynik funkcji IEnumerable.Count () może być nieprawidłowy. To jest bardzo prosta próbka do przetestowania:
Wynik musi wynosić (7,7,3,3), ale rzeczywisty wynik to (7,7,3,17)
źródło
Najlepszym sposobem, jaki znalazłem, jest przeliczenie na listę.
źródło
Sugerowałbym wywołanie ToList. Tak, wyliczasz wcześniej, ale nadal masz dostęp do swojej listy elementów.
źródło
Może nie dawać najlepszej wydajności, ale możesz użyć LINQ do zliczenia elementów w IEnumerable:
źródło
Myślę, że najłatwiej to zrobić
Odniesienie: system.linq.enumerable
źródło
Używam
IEnum<string>.ToArray<string>().Length
i działa dobrze.źródło
IEnum<string>.Count();
”?Używam takiego kodu, jeśli mam listę ciągów:
źródło