Operacje na tablicach i manipulacje ciągami znaków to jedne z najczęściej wykonywanych działań w codziennej pracy programisty. Nawet podczas rozmów kwalifikacyjnych sprawdzana jest taka wiedza, choć to w zasadzie wiedza podstawowa z zakresu algorytmów. Jednak to w jaki sposób rozwiążesz takie lub podobne zadanie może dodatkowo świadczyć o twoich umiejętnościach. Zatem ile znasz sposobów posumowania elementów w JS.

Problem

Zakładamy, że nasza tablica arr zawiera n liczb całkowitych dodatnich. Jako wynik zwracamy sumę wszystkich elementów tablicy. Ile istnieje różnych sposobów rozwiązania tego problemu?

Pętla for

Pierwszy sposób, który przychodzi mi do głowy jest chyba najpopularniejszym według mnie. Liczba elementów tablicy jest łatwa do uzyskania, a pętla for jedną z pierwszych instrukcji jakie poznajemy ucząc się programowania. Przynajmniej tak było, kiedy ja uczyłem się programowania.


var sum = 0;
for (var i = 0; i < arr.length; i++) {
  sum += arr[i];
}

W sumie nic wielkiego, a tłumaczenie wydaje się zbędne, ale dla pewności. Pętla for działa na zasadzie warunku początkowego i końcowego. Kiedy ten drugi przestanie być prawdziwy to pętla kończy działanie. Podczas każdej iteracji wykonywany jest kod wewnątrz pętli, co w naszym przypadku jest dodawaniem kolejnych elementów tablicy, a następnie warunek inkrementacji o ile istnieje.

Pętla do...while

Taka pętla będzie wykonywała instrukcje wewnątrz, dopóki warunek pętli nie zwróci false. Znowu sumowanie wszystkich elementów wymaga iteracji całej tablicy.


sum = 0;
i = 0;
do {
  sum += arr[i];
  i++;
} while (i < arr.length)

W naszym przypadku warunek wyjścia z pętli oprzemy się indeksy kolejnych elementów porównywane z wielkością tablicy. Sam indeks będzie zwiększany wewnątrz bloku pętli, a początkowo ustawiony przed pętlą.

Pętla while

Podobnie jak w pierwszym wypadku pętla wykonuje określoną liczbę iteracji, dopóki warunek pętli będzie prawdziwy. Policzenie sumy dalej sprawdza się do dodawania kolejnych elementów tablicy.


var sum = 0;
var i = 0;
while (i < arr.length) {
  sum += arr[i];
  i++;
}

Różnica polega na określeniu warunku początkowego przed pętlą oraz sposobu inkrementacji wewnątrz bloku pętli. Istotne z punktu przetwarzania danych wewnątrz pętli jest moment, w którym dokonujemy zmiany zmiennej i. Liczba obrotów pętli nie ulegnie zmianie, ale sama wartość w chwili sumowania będzie inna niż oczekiwana.

Całość dalej oparta jest o sumowanie elementów, ale warunek pętli stanowi tylko długość tablicy, która z każdą iteracją będzie zmniejszała się, ponieważ wywołanie pop() zwraca ostatni element tablicy i zmniejsza wielkość. Minusem takiego rozwiązania jest pusta tablica arr po wykonaniu sumowania, więc inne operacje nie będą już możliwe.


var sum = 0;
while (arr.length) {
  sum += arr.pop();
}

Pętla while może być zapisana jeszcze prościej, mianowicie z użyciem funkcji pop().

Pętla forEach

Wspomniane wcześniej pętle wymagają określenia warunków wyjścia, dzięki czemu możliwe jest wyjście z pętli w dowolnym momencie (bez iterowania wszystkich elementów). Akurat w przypadku sumowania tablicy konieczne jest iterowanie wszystkich elementów, co zapewnia pętla forEach.


var sum = 0;
arr.forEach(function(itm, i) {
  sum += itm[i];
})

Funkcja zwrotna jest przekazywana jak pierwszy argument wywołania forEach(). Wewnątrz funkcji istnieje dostęp do elementu tablicy jak również indeksu iteracji. Wtedy sumowanie kolejnych elementów jest równie proste jak w poprzednich przypadkach.

Pętla for...in

Kolejna pętla również iteruje wszystkie elementy obiektu podanego wewnątrz funkcji. Choć dokładniej mówiąc są do własności obiektu. Składnia wywołania jest bardzo naturalna i podobna do tej znanej z innych języków.


var sum = 0;
for (var i in arr) {
  sum += arr[i];
})

Istotny w przypadku pętli jest fakt, że zmienna i w każdej iteracji własnością obiektu iterowanego. Zatem dla tablicy będą to indeksy kolejnych elementów. Ważne jest, że w momencie kiedy do tablicy zostanie dodany element spoza wielkości tablicy to zmieni się rozmiar tablicy, który wtedy nie będzie odzwierciedlał rzeczywistej liczby elementów. Przykładowo:


var arr = [10, 20, 30];
arr[5] = 50;
console.log(arr.length); // 6
console.log(arr); // [10, 20, 30, , ,50]

Tablica działa w JS w ten sposób, że jej wielkość stanowi ostatni indeks zwiększony od jeden. Zatem, jeśli dodany zostanie element pod indeksem 5 to rozmiar tablicy będzie równy 6. Chociaż sama tablica będzie zawierała tylko 4 liczby, to w rzeczywistości posiada 6 elementów, ale arr[3] i arr[4] mają wartości undefined.

Jeszcze ważniejsze jest gdybyśmy do tablicy dodali inną własność. Pamiętajmy, że tablica w rzeczywistości jest obiektem.


var arr = [1, 2, 3, 4]; 
arr.foo = 'bar';
for (var i in arr) {
  console.log(i);
}

Wtedy pętla wyświetli nie tylko indeksy naszej tablicy, ale także foo.

Pętla for...of

Następna pętla działa podobnie, ale w ramach każdej iteracji mamy bezpośredni dostęp do wartości. W ten sposób nie odwołujemy się do danego elementu tablicy, a konkretnej wartości poprzez zmienną i.


var sum = 0;
for (var i of arr) {
  sum += i;
})

Różnica w porównaniu z pętlą for...in sprowadza się do tego, że wartości dodatkowych własności obiektu nie będą wyświetlone.


var arr = [1, 2, 3, 4]; 
arr.foo = 'bar';
for (var i of arr) {
  console.log(i);
}

Tym razem pętla wyświetli kolejno: 1, 2, 3, 4, ale bez bar.

Metoda reduce()

Programowanie funkcyjne stało się w ostatnich latach bardzo popularne, o czym niech świadczą również funkcje dodane w specyfikacji ECMAScript 6. Pierwszym argumentem funkcji reduce() jest funkcja zwrotna, a drugim opcjonalnym wartość początkowa.


var sum = arr.reduce(function(prev, curr) {
  return prev + curr;
});

Ogólnie rzecz biorąc to reduce() wywołuje funkcję względem wartości przyrostowej z każdego wywołania i kolejnego elementu tablicy (od lewej do prawej) w celu sprowadzenia tej tablicy do pojedynczej wartości.

Podsumowanie

To tylko kilka i podstawowe sposoby wyliczenia sumy elementów tablicy. W większości sprowadzały się do sumowania kolejnych elementów iterowanej tablicy. Jeśli znasz jeszcze inne, bardziej oryginalne sposoby to podziel się nimi w komentarzach.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *