2010-12-31 10 views

Odpowiedz

18

ToArray niekoniecznie jest szybszy niż ToList. Po prostu użyj ToList.

Punkt jest tak długi, jak długo nie znasz liczby elementów oryginalnej sekwencji przed wyliczeniem, kończy się zmiana rozmiaru tablicy i dodawanie do niej elementów takich jak List<T>, więc ToArray będzie musiał wykonać to samo robi List<T>. Poza tym ToList daje ci List<T> i jest ładniejszy niż surowa tablica.

Oczywiście, jeśli znasz konkretny typ instancji IEnumerable<T>, mogą istnieć szybsze metody, ale nie jest to istotne.

Nota boczna: użycie tablicy (chyba że musisz) jest prawdopodobnie mikro-optymalizacją i powinno być avoidedmost of the time.

+0

Uwaga: są one praktycznie równoważne. – Vadim

+0

@Yads: dokładnie. –

+1

+1. W rzeczywistości Mono ['Enumerable.ToArray'] (https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Linq/Enumerable.cs#L2794) używa' nowej listy (źródło) .ToArray() ', chyba że' IEnumerable 'dzieje się jako' ICollection '. Nie byłbym zaskoczony, gdyby stwardnienie rozsiane było podobne. –

2

Drugim najtańszym sposobem jest podanie new List<T>(myEnumerable).ToArray(). Najtańszym sposobem jest użycie albo .ToArray() (z LINQ) lub, jeśli nie masz C# 3.5, aby utworzyć własny bufor i dodać do niego, podwajając jego rozmiar, a następnie przyciąć go na końcu.

5

Enumerable::ToArray i Enumerable::ToList ostatecznie użyciu tej samej techniki, aby otrzymać elementy od źródła do bufora tablicy wewnętrznego, a po osiągnięciu wielkości tego buforu będą przydziela nowy bufor dwukrotnie większy, memcpy się i dalej dodawać elementy, powtarzając ten proces, aż zakończy się wyliczanie źródła. Różnica na końcu polega na tym, że ToArray, która wewnętrznie korzysta z implementacji Buffer<T>, musi następnie przydzielić dokładnie rozmiar Array i skopiować elementy do niej przed zwróceniem wyniku. Z drugiej strony, ToList po prostu musi zwrócić List<T> z potencjalnie (prawdopodobnie) tylko częściowo wypełnionym buforem tablicowym wewnątrz niego.

Obie implementacje mają również optymalizację gdzie jeśli źródłem IEnumerable jest ICollection będą one rzeczywiście przeznaczyć dokładnie odpowiedni rozmiar bufora, aby rozpocząć z użyciem ICollection::Count a następnie użyć ICollection::CopyTo od źródła do wypełnienia swoich buforów.

Na koniec okaże się, że zachowują się prawie identycznie w większości sytuacji, ale List<T> jest technicznie "cięższą" klasą, do której można się przyczepić, a ToArray ma dodatkowy przydział + memcpy na końcu (jeśli źródłem nie jest ICollection), aby móc przekazać dokładnie odpowiednią wielkość tablicy. Zwykle trzymam się z ToList, chyba że wiem, że muszę przekazać wynik do czegoś, co wymaga tablicy, powiedzmy może Task::WaitAll.

4

Chciałem zasugerować możliwość użycia , jeśli masz do dyspozycji TPL, ale nieformalne testy na moim dwurdzeniowym laptopie pokazują, że jest on 7 razy wolniejszy niż tylko .ToList(). Więc trzymaj się z Mehrdad'sanswer.

+1

+1 Jest to potencjalnie dobra alternatywa, a w zależności od charakteru obiektu odbiorcy może być znacznie szybsza, ale ta kategoria jest "nieistotna do punktu". –

0

Wiem, że to dość stary ...

Dlaczego nie można zrobić coś takiego ...

IEnumerable <T> original = {... wstaw tutaj kod do wypełnienia ...};

IEnumerable <T> copy = (z rzędu w oryginalnym wybranym wierszu);

Użyłem tej metody wcześniej, aby odłożyć ładowanie kopii i jej elementów, dopóki ich nie potrzebuję, oraz, że nie zmienię podstawowego typu danych na "oryginalny", przesyłając go do typu listy.

+0

Wybór tożsamości tak naprawdę nie daje niczego tutaj. Nie jest to tak naprawdę funkcjonalnie odmienne od kopiowania odniesienia do innego "IEnumerable", inne niż to, że dodaje trochę dodatkowych kosztów w czasie wykonywania i zapobiega rzutowaniu na ukryty typ. Jeśli chcesz uzyskać migawkę tego, jak wygląda sekwencja w danym momencie, właściwym rozwiązaniem jest 'ToList'. Jeśli nie, a chcesz sekwencji, która jest generowana w tym samym dworze, co druga sekwencja, po prostu skopiuj referencję; nie trzeba robić nic więcej. – Servy

Powiązane problemy