Skip to content

Commit

Permalink
Добавляет ответ на вопрос с собеседования про reduce() (#4689)
Browse files Browse the repository at this point in the history
* Немного правит описание вопроса

* Создает директорию и файл для ответа

* Создает ответ

* Чуть-чуть исправляет коллегу согласно требованиям

* Немного убирает лишнее

* Добавляет двойной пробел

* Расставляет ё

* Принимаю предложенное исправление

Co-authored-by: Polina Gurtovaya <zloymult@gmail.com>

* Правит ответ – поднимает правильное решение на первое место и рассказывает про возможные ошибки ниже.

* Отбивает пустые строки, успокаивает спеллер

* Возвращает потерявшуюся ё

---------

Co-authored-by: Tatiana Fokina <fokinatatian@gmail.com>
Co-authored-by: Polina Gurtovaya <zloymult@gmail.com>
  • Loading branch information
3 people authored Sep 23, 2023
1 parent b41ef5c commit f746225
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
79 changes: 79 additions & 0 deletions interviews/sum-function/answers/arudenkoofficial/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
### Решение

Эта задача решается буквально в одну строчку. Давайте посмотрим на решение, а затем немного разберём его.

```javascript
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue);

sum(1, 2, 3); // 6
sum('1', 2, 3); // '123'
sum(1); // 1
```

По условиям мы не знаем, какое количество аргументов будет передано. Мы используем синтаксис остаточных параметров (_rest_) в сигнатуре функции. Это позволит преобразовать любое количество аргументов функции в массив `args`.

С массивом гораздо удобнее работать – мы можем использовать метод [`Array.reduce()`](/js/array-reduce/). Его колбэк будет вызываться для каждого элемента массива, и значение каждого аргумента будет прибавляться к значению в аккумуляторе. Когда начальное значение аккумулятора не указано, метод использует первый элемент массива, а выполнение колбэк начнёт со второго элемента.

### Какую ошибку легко допустить

Мы обсудили выше, что [`reduce()`](/js/array-reduce/) в своём колбэке использует аккумулятор – это переменная, которая накапливает в себе результаты прошлых итераций. Часто, используя [`reduce()`](/js/array-reduce/) мы передаём начальное значение аккумулятора.

```javascript
// Если мы хотим получить из массива объект, то стартовым значением аккумулятора будет объект

const list = [
{ key: 'name', value: 'John' },
{ key: 'age', value: 30 },
{ key: 'city', value: 'New York' }
];

const obj = list.reduce((accumulator, currentItem) => {
accumulator[currentItem.key] = currentItem.value;
return accumulator;
}, {});
```

При решении задач, в которых необходимо складывать значения, часто хочется указать ноль в качестве стартового значения. Это интуитивное и очень понятное на первый взгляд желание – к нулю удобно прибавлять и отрицательные, и положительные числа.

Давайте разберём такой вариант этой функции, в которой мы укажем ноль как стартовое значение:

```javascript
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue, 0);

sum(1, 2, 3); // 6
sum('1', 2, 3); // '0123'
```

Пока мы имеем дело с числами – результат ожидаемый. Но почему результат выполнения во втором примере с нулём?

#### Неявное преобразование типов

Да, дело в той особенности языка, которая дарит нам столько весёлых шуток про JavaScript.

Оператор сложения приводит оба операнда к строковому формату в случае, если хотя бы один из них – строка. Таким образом мы и получаем `0125` в примере выше – на первой же итерации строка `'1'` складывается с нулём, заданным как первоначальное значение для [`reduce()`](/js/array-reduce/).

Давайте вернёмся к первому решению задачи и посмотрим детальнее, как там решается эта проблема.

```javascript
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue);

sum('1', 2, 3); // '123'
```

На первой итерации аккумулятор будет равен значению первого элемента в массиве, а мы получим на первой итерации вот такую операцию: `'1' + 2`. Как я писал выше, бинарный оператор `+` приведёт оба операнда к строковому формату в случае, если хотя бы один из них – строка.

Пока в массиве встречаются числа – они будут арифметически складываться. Как только в ряду аргументов наш колбэк встретит строку, он начнёт приводить все аргументы к строке и конкатенировать их.

#### Граничный случай

Мы успешно справились с главным условием! Но теперь давайте подумаем, как быть, когда в функцию `sum()` не передали вообще никаких аргументов? Просто проверим, что длина массива ненулевая. _Rest_-синтаксис создаст пустой массив, если не будет передано никаких аргументов:

```javascript
const sum = (...args) => args.length ? args.reduce((acc, currentValue) => acc + currentValue) : 0;

sum('1', 2, 3); // '123'
sum(1, 2, 3); // 6
sum(); // 0
```

Мы используем [тернарный оператор](/js/ternary-operator/) для проверки длины массива, а наша функция по-прежнему умещается лишь в одну строку!
2 changes: 1 addition & 1 deletion interviews/sum-function/answers/vladislavsrtkn/index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
В такой задаче у вас хотят проверить два навыка: владение методом массивов **reduce** и использование [**спред-синтаксиса**](https://doka.guide/js/spread/) в качестве аргумента функции.
В такой задаче у вас хотят проверить два навыка: владение методом массивов **reduce** и использование [**спред-синтаксиса**](/js/spread/) в качестве аргумента функции.

Давайте создадим такую функцию, назовём её `sumOrConcat`:

Expand Down
6 changes: 3 additions & 3 deletions interviews/sum-function/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ author: arudenkoofficial
Напишите функцию, которая принимает любое количество аргументов типа `String` или `Number` и возвращает их сумму, если все аргументы являются числами, или конкатенирует их по правилам JS, если хотя бы один аргумент является строкой.

```js
1,2,5 => 8
1,2,'5' => '35'
'1', 2, 5 => '125'
sum(1, 2, 5); // 8
sum(1, 2, '5'); // '35'
sum('1', 2, 5); // '125'
```

0 comments on commit f746225

Please sign in to comment.