pętla for vs chaining vs .reduce()
Tags: arrays, javascript, typescript, comparison
Published: 2021-10-08 15:38:51

> Przetłumaczona wersja [artykułu](https://kentcdodds.com/blog/array-reduce-vs-chaining-vs-for-loop) [Kenta C. Doddsa](https://kentcdodds.com/about)

Jedną z operacji w trakcie przenoszenia mojego internetowego życia, było pobranie wszystkich zdjęć z Google Photos. Uznałem, że potrzebuję zmiany ich organizacji, toteż napisałem do tego prosty skrypt. To, co robił nie jest istotne dla tego artykułu, więc nie będę opisywał szczegółów (tutaj [cała sytuacja](https://gist.github.com/kentcdodds/59daa81d46ba51b926a6a2f044aa5ad6), jeśli chcesz o tym poczytać). Oto fragment o którym chciałbym coś powiedzieć (zredagowany dla czytelności):

```js
const lines = execSync(`find "${searchPath}" -type f`).toString().split('\n')

const commands = lines
  .map(f => f.trim())
  .filter(Boolean)
  .map(file => {
    const destFile = getDestFile(file)
    const destFileDir = path.dirname(destFile)
    return `mkdir -p "${destFileDir}" && mv "${file}" "${destFile}"`
  })

commands.forEach(command => execSync(command))
```
Zasadniczo wszystko, co się tutaj dzieje, to użycie polecenia `find`, aby znaleźć listę plików w katalogu, a następnie rozdzielenie wyniku na wiersze, pozbycie się białych znaków, mapowanie ich na polecenia, a później wykonanie tych poleceń. 

Udostępniłem ten skrypt na [Twitterze](https://twitter.com/kentcdodds/status/1215785900413599744) i kilka osób krytykowało to, że nie użyłem metody `.reduce()`. Jestem prawie pewien, że sugerowali to jako wskazówkę do optymalizacji, ponieważ możemy dzięki temu zmniejszyć liczbę pętli po tablicy. 

Żeby było jasne, było tam około 50 tysięcy pozycji, więc zdecydowanie więcej, niż zazwyczaj mamy przy tworzeniu interfejsu. Chciałbym jednak zwrócić uwagę, że w przypadku jednorazowych skryptów wydajność nie jest aż tak ważna (chyba, że to co robisz jest naprawdę obciążające). W moim przypadku działało to bardzo szybko. Powolna część nie polegała na wielokrotnym iterowaniu po tablicy elementów, ale na [uruchamianiu poleceń](https://twitter.com/kentcdodds/status/1215810104261369856). 

Inni mówili, bym używał API od Node-a lub modułów open source z npm, aby ułatwić uruchamianie tych skryptów, ponieważ "prawdopodobnie byłoby to szybsze i działałoby na różnych platformach". Ponownie, najpewniej mają rację, ale w przypadku jednorazowych skryptów, które są "wystarczająco szybkie" te rzeczy nie mają znaczenia. Jest to klasyczny przykład nakładania nieistotnych ograniczeń na program, co skutkuje bardziej skomplikowanym rozwiązaniem. 

W każdym razie, chciałem przyjrzeć się kwestii użycia `.reduce()` zamiast `.map()` lub `.filter()`.

## `.reduce()`

Oto jak wyglądałby ten sam kod z użyciem `.reduce()`:

```js
const commands = lines.reduce((accumulator, line) => {
  let file = line.trim()
  if (file) {
    const destFile = getDestFile(file)
    const destFileDir = path.dirname(destFile)
    accumulator.push(`mkdir -p "${destFileDir}" && mv "${file}" "${destFile}"`)
  }
  return accumulator
}, [])
```

Nie jestem jedną z tych osób, które uważają, że używanie `.reduce()` jest [złe](https://twitter.com/jaffathecake/status/1213077702300852224)
(sprawdź ten wątek, po więcej ciekawych przykładów użycia `.reduce()`), ale myślę, że jestem w stanie rozpoznać, kiedy kod jest prostszy/bardziej skomplikowany i muszę przyznać, że przykład z użyciem chaining-u jest zdecydowanie prostszy.

## Pętla

Szczerze, używam metod tablicowych tak długo, że potrzebuję chwili by napisać to z użyciem pętli. Jedną chwileczkę...

```js
const commands = []
for (let index = 0; index < lines.length; index++) {
  const line = lines[index]
  const file = line.trim()
  if (file) {
    const destFile = getDestFile(file)
    const destFileDir = path.dirname(destFile)
    commands.push(`mkdir -p "${destFileDir}" && mv "${file}" "${destFile}"`)
  }
}
```

To też nie jest dużo prostsze.

EDIT: ALE CZEKAJ! Możemy to uprościć za pomocą `for...of`!

```js
const commands = []
for (const line of lines) {
  const file = line.trim()
  if (!file) continue

  const destFile = getDestFile(file)
  const destFileDir = path.dirname(destFile)
  commands.push(`mkdir -p "${destFileDir}" && mv "${file}" "${destFile}"`)
}
```

Osobiście uważam, że nie jest to dużo lepsze niż tradycyjna pętla, ale sądzę, że jest całkiem proste. Niektórzy uważają pętle za zbyt "imperatywne", ale niekiedy są przydatne.

## Podsumowanie

Często będę wybierać pomiędzy chaining-iem, a pętlą `for...of`. Jeśli pojawi się problem z wielokrotnym iterowaniem po tablicy to z pewnością zdecyduję się na `for...of`.

Osobiście nie używam często metody `.reduce()`, ale czasami ją wykorzystuję. Zdaję sobie sprawę, jak subiektywnie to brzmi, ale tak duża część programowania jest subiektywna 🤷‍♂️

Daj mi znać co o tym myślisz!