Czy istnieje lepszy krótszy sposób niż iterowanie po tablicy?
int[] arr = new int[] { 1, 2, 3 };
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
wyjaśnienie:
Lepszy podstawowy oznacza czystszy kod, ale wskazówki dotyczące poprawy wydajności są również mile widziane. (Jak już wspomniano: dzielenie dużych tablic).
To nie tak, że szukałem zabójczej poprawy wydajności - po prostu zastanawiałem się, czy ten rodzaj cukru syntaktycznego nie był już dostępny: „Jest String.Join - co do cholery z int []?”.
Odpowiedzi:
Pod warunkiem, że możesz używać .NET 3.5 (lub nowszego) i LINQ, wypróbuj
źródło
System.OverflowException
jeśli wynik będzie większy niż można zmieścić w 32-bitowej liczbie całkowitej ze znakiem (tj. (2 ^ 31) -1 lub po angielsku ~ 2,1 miliarda).int sum = arr.AsParallel().Sum();
szybsza wersja, która wykorzystuje wiele rdzeni procesora. Aby tego uniknąćSystem.OverflowException
, możesz użyćlong sum = arr.AsParallel().Sum(x => (long)x);
Dla jeszcze szybszych wersji, które unikają wyjątku przepełnienia i obsługują wszystkie typy danych całkowitoliczbowych i używają równoległych instrukcji SIMD / SSE danych, spójrz na pakiet nuget HPCsharpTak jest. Z .NET 3.5:
Jeśli nie używasz .NET 3.5, możesz to zrobić:
źródło
foreach
Pętla jest dostępny we wszystkich wersjach C #.foreach
po prostu zastępuje jeden wiersz kodu innym i nie jest krótszy. Poza tym aforeach
jest w porządku i jest bardziej czytelny.foreach (int i in arr) sum += i;
Z LINQ:
źródło
To zależy od tego, jak lepiej zdefiniujesz. Jeśli chcesz, aby kod wyglądał bardziej czytelnie, możesz użyć .Sum (), jak wspomniano w innych odpowiedziach. Jeśli chcesz, aby operacja przebiegała szybko i masz dużą tablicę, możesz ją wykonać równolegle, dzieląc ją na sumy częściowe, a następnie zsumuj wyniki.
źródło
Alternatywą jest również użycie
Aggregate()
metody rozszerzenia.źródło
Jeśli nie wolisz LINQ, lepiej jest użyć pętli foreach, aby uniknąć braku indeksu.
źródło
W przypadku bardzo dużych tablic może się opłacić wykonanie obliczeń przy użyciu więcej niż jednego procesora / rdzeni maszyny.
źródło
Jednym z problemów z powyższymi rozwiązaniami pętli for jest to, że dla następującej tablicy wejściowej ze wszystkimi dodatnimi wartościami suma wyników jest ujemna:
Suma wynosi -2147483648, ponieważ wynik dodatni jest zbyt duży dla typu danych int i powoduje przepełnienie do wartości ujemnej.
Dla tej samej tablicy wejściowej sugestie arr.Sum () powodują zgłoszenie wyjątku przepełnienia.
Bardziej niezawodnym rozwiązaniem jest użycie większego typu danych, takiego jak „long” w tym przypadku, dla „sumy” w następujący sposób:
To samo ulepszenie działa w przypadku sumowania innych typów danych całkowitych, takich jak short i sbyte. W przypadku tablic liczb całkowitych bez znaku, takich jak uint, ushort i bajt, użycie długości bez znaku (ulong) dla sumy pozwala uniknąć wyjątku przepełnienia.
Rozwiązanie pętli for jest również wielokrotnie szybsze niż Linq .Sum ()
Aby działać jeszcze szybciej, pakiet nuget HPCsharp implementuje wszystkie te wersje .Sum (), a także wersje SIMD / SSE i wielordzeniowe wersje równoległe, co zapewnia wielokrotnie wyższą wydajność.
źródło
long sum = arr.Sum(x => (long)x);
który dobrze działa w C # przy użyciu Linq. Zapewnia pełną dokładność sumowania wszystkich typów danych całkowitych ze znakiem: sbyte, short i int. Unika również zgłaszania wyjątku przepełnienia i jest ładnie zwarty. Nie jest tak wydajna, jak powyższa pętla for, ale nie we wszystkich przypadkach jest potrzebna.Użycie foreach byłoby krótszym kodem, ale prawdopodobnie wykonaj dokładnie te same kroki w czasie wykonywania po tym, jak optymalizacja JIT rozpozna porównanie z długością w wyrażeniu sterującym pętli for.
źródło
W jednej z moich aplikacji użyłem:
źródło
.Aggregate()
metody rozszerzenia.Ulepszenie ładnej wielordzeniowej implementacji równoległej Theodora Zouliasa.
który działa dla typów danych całkowitych bez znaku, ponieważ C # obsługuje tylko Interlocked.Add () dla int i long. Powyższą implementację można również łatwo zmodyfikować, aby obsługiwała inne typy danych całkowitoliczbowych i zmiennoprzecinkowych, aby wykonywać sumowanie równolegle przy użyciu wielu rdzeni procesora. Jest używany w pakiecie nuget HPCsharp.
źródło
Wypróbuj ten kod:
Wynik to:
źródło