Czasami można zaobserwować następujący kod:
int[] firstArray = Enumerable.Range(1, 1000).ToArray(); int[] secondArray = Enumerable.Range(1, 1000).ToArray(); foreach (int item in firstArray) { Process(item); } foreach (int item in secondArray) { Process(item); }
Mam na myśli sytuacje kiedy mamy kilka osobnych tablic, ale przetwarzanie ich jest takie same lub bardzo podobne. Inny przykład to przetworzenie tablicy, a potem pojedynczego elementu pochodzącego z innego źródła:
int[] firstArray = Enumerable.Range(1, 1000).ToArray(); var singleItem=GetItem(...); foreach (int item in firstArray) { Process(item); } Process(singleItem);
W skrócie, w kodzie takim występujące kilka źródeł danych albo pojedyncze elementy. Tworzenie kilku pętli, jak wyżej jest brzydkie i niewygodne. Lepiej skorzystać z LINQ i złączyć kilka źródeł w jedno. Możemy to zrobić za pomocą concat albo union:
int[] firstArray = Enumerable.Range(1, 1000).ToArray(); int[] secondArray = Enumerable.Range(1, 1000).ToArray(); foreach (int item in firstArray.Union(secondArray)) { Process(item); } foreach (int item in firstArray.Concat(secondArray)) { Process(item); }
Jaka jest różnica między union a concat? Union złączy tylko unikalne elementy czyli to tak jakby wywołać concat a potem na końcu Distinct(), który zwraca wyłącznie unikalne liczby. Oczywiście ma to ogromny wpływ na wydajność ponieważ należy w przypadku union wywoływać Equals oraz GetHash:
private static void Main(string[] args) { int[] firstArray = Enumerable.Range(1, n).ToArray(); int[] secondArray = Enumerable.Range(1, n).ToArray(); TestConcat(firstArray,secondArray); TestUnion(firstArray,secondArray); } private static void TestUnion(int[] array1, int[] array2) { for (int i = 0; i < Tests; i++) { Stopwatch stopwatch = Stopwatch.StartNew(); foreach (var item in array1.Union(array2)) { } Console.WriteLine("Union: {0}", stopwatch.ElapsedTicks); } } private static void TestConcat(int[] array1, int[] array2) { for (int i = 0; i < Tests; i++) { Stopwatch stopwatch = Stopwatch.StartNew(); foreach (var item in array1.Concat(array2)) { } Console.WriteLine("Concat: {0}",stopwatch.ElapsedTicks); } }
Wynik:
Sprawa może wydawać się łatwa ale czasami, gdy kod jest bardziej skomplikowany nie jest zbyt oczywista. W praktyce, nie zawsze mamy dokładnie te same typy i wtedy należy dokonać np. transformacji aby ujednolicić przetwarzane dane.
Czy nie lepiej zmodyfikować (lub stworzyć metodę enkapsulującą) metodę Process() aby przyjmowała zmienną liczbę argumentów (deklaracja params)?
Dzięki temu ograniczymy nadmierny kod, a przy okazji będzie go można wykorzystać zarówno do tablic jak i pojedynczych obiektów