renovations
This commit is contained in:
parent
4b8b168fd2
commit
c7d4c7e3ff
172 changed files with 869 additions and 244 deletions
|
@ -0,0 +1,15 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = ["Есть", "жизнь", "на", "Марсе"];
|
||||
|
||||
*!*
|
||||
var arrLength = arr.map(function(item) {
|
||||
return item.length;
|
||||
});
|
||||
*/!*
|
||||
|
||||
alert( arrLength ); // 4,5,2,5
|
||||
```
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Перепишите цикл через map
|
||||
|
||||
[importance 5]
|
||||
|
||||
Код ниже получает из массива строк новый массив, содержащий их длины:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = ["Есть", "жизнь", "на", "Марсе"];
|
||||
|
||||
*!*
|
||||
var arrLength = [];
|
||||
for(var i=0; i<arr.length; i++) {
|
||||
arrLength[i] = arr[i].length;
|
||||
}
|
||||
*/!*
|
||||
|
||||
alert( arrLength ); // 4,5,2,5
|
||||
```
|
||||
|
||||
Перепишите выделенный участок: уберите цикл, используйте вместо него метод `map`.
|
|
@ -0,0 +1,12 @@
|
|||
function getSums(arr) {
|
||||
var result = [];
|
||||
if (!arr.length) return result;
|
||||
|
||||
var totalSum = arr.reduce(function(sum, item) {
|
||||
result.push(sum);
|
||||
return sum + item;
|
||||
});
|
||||
result.push(totalSum);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
describe("getSums", function() {
|
||||
|
||||
it("частичные суммы [1,2,3,4,5] равны [1,3,6,10,15]", function() {
|
||||
assert.deepEqual( getSums([1,2,3,4,5]), [1,3,6,10,15]);
|
||||
});
|
||||
|
||||
it("частичные суммы [-2,-1,0,1] равны [-2,-3,-3,-2]", function() {
|
||||
assert.deepEqual( getSums([-2,-1,0,1]), [-2,-3,-3,-2]);
|
||||
});
|
||||
|
||||
it("частичные суммы [] равны []", function() {
|
||||
assert.deepEqual( getSums([]), [] );
|
||||
});
|
||||
|
||||
it("частичные суммы [1] равны [1]", function() {
|
||||
assert.deepEqual( getSums([1]), [1] );
|
||||
});
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
Метод `arr.reduce` подходит здесь идеально. Достаточно пройтись по массиву слева-направа, накапливая текущую сумму в переменной и, кроме того, добавляя её в результирующий массив.
|
||||
|
||||
Неправильный вариант может выглядеть так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function getSums(arr) {
|
||||
var result = [];
|
||||
if (!arr.length) return result;
|
||||
|
||||
arr.reduce(function(sum, item) {
|
||||
result.push(sum);
|
||||
return sum + item;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
alert(getSums([1,2,3,4,5])); // результат: *!*1,3,6,10*/!*
|
||||
```
|
||||
|
||||
Перед тем, как читать дальше, посмотрите на него внимательно. Заметили, в чём ошибка?
|
||||
|
||||
Если вы его запустите, то обнаружите, что результат не совсем тот. В получившемся массиве всего четыре элемента, отсутствует последняя сумма.
|
||||
|
||||
Это из-за того, что последняя сумма является результатом метода `reduce`, он на ней заканчивает проход и далее функцию не вызывает, поэтому она оказывается не добавленной в `result`.
|
||||
|
||||
Исправим это:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
function getSums(arr) {
|
||||
var result = [];
|
||||
|
||||
*!*var totalSum*/!* = arr.reduce(function(sum, item) {
|
||||
result.push(sum);
|
||||
return sum + item;
|
||||
});
|
||||
*!*result.push(totalSum);*/!*
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
alert(getSums([1,2,3,4,5])); // *!*1,3,6,10,15*/!*
|
||||
alert(getSums([-2,-1,0,1])); // *!*-2,-3,-3,-2*/!*
|
||||
```
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Массив частичных сумм
|
||||
|
||||
[importance 2]
|
||||
|
||||
На входе массив чисел, например: `arr = [1,2,3,4,5]`.
|
||||
|
||||
Напишите функцию `getSums(arr)`, которая возвращает массив его частичных сумм.
|
||||
|
||||
Иначе говоря, вызов `getSums(arr)` должен возвращать новый массив из такого же числа элементов, в котором на каждой позиции должна быть сумма элементов `arr` до этой позиции включительно.
|
||||
|
||||
То есть:
|
||||
|
||||
```js
|
||||
для arr = [1,2,3,4,5]
|
||||
getSums(arr) = [1, 1+2, 1+2+3, 1+2+3+4, 1+2+3+4+5] = [1, 3, 6, 10, 15]
|
||||
```
|
||||
|
||||
Еще пример: `getSums([-2,-1,0,1]) = [-2,-3,-3,-2]`.
|
||||
|
||||
<ul>
|
||||
<li>Функция не должна модифицировать входной массив.</li>
|
||||
<li>В решении используйте метод `arr.reduce`.</li>
|
||||
</ul>
|
227
1-js/4-data-structures/9-array-iteration/article.md
Normal file
227
1-js/4-data-structures/9-array-iteration/article.md
Normal file
|
@ -0,0 +1,227 @@
|
|||
# Массив: перебирающие методы
|
||||
|
||||
Современный стандарт JavaScript предоставляет много методов для "умного" перебора массивов, которые есть в современных браузерах...
|
||||
|
||||
...Ну а для их поддержки в IE8- просто подключите библиотеку [ES5-shim](https://github.com/kriskowal/es5-shim).
|
||||
[cut]
|
||||
## forEach
|
||||
|
||||
Метод ["arr.forEach(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) используется для перебора массива.
|
||||
|
||||
Он позволяет перебрать массив при помощи функции `callback`, что зачастую гораздо элегантнее, нежели цикл `for`.
|
||||
|
||||
Функция `callback` вызывается для каждого элемента с тремя параметрами `callback(item, i, arr)`:
|
||||
|
||||
<ul>
|
||||
<li>`item` -- очередной элемент массива.</li>
|
||||
<li>`i` -- его номер.</li>
|
||||
<li>`arr` -- массив, который перебирается.</li>
|
||||
</ul>
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = ["Яблоко", "Апельсин", "Груша"];
|
||||
|
||||
function show(item, i, arr) {
|
||||
alert(i + ": " + item + " (массив:" + arr + ")");
|
||||
}
|
||||
|
||||
arr.forEach(show);
|
||||
```
|
||||
|
||||
Второй, необязательный аргумент `forEach` позволяет указать контекст `this` для `callback`. Мы обсудим его в деталях чуть позже, сейчас он нам не важен.
|
||||
|
||||
Метод `forEach` ничего не возвращает, его используют только для перебора.
|
||||
|
||||
## filter
|
||||
|
||||
Метод ["arr.filter(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter) используется для *фильтрации* массива через функцию.
|
||||
|
||||
Он создаёт новый массив, в который войдут только те элементы `arr`, для которых вызов `callback(item, i, arr)` возвратит `true`.
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1, -1, 2, -2, 3];
|
||||
|
||||
function isPositive(number) {
|
||||
return number > 0;
|
||||
}
|
||||
|
||||
*!*
|
||||
var positiveArr = arr.filter(isPositive);
|
||||
*/!*
|
||||
|
||||
alert(positiveArr); // 1,2,3
|
||||
```
|
||||
|
||||
## map
|
||||
|
||||
Метод ["arr.map(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map) используется для *трансформации* массива.
|
||||
|
||||
Он создаёт новый массив, который будет состоять из результатов вызова `callback(item, i, arr)` для каждого элемента `arr`.
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1, 2, 3, 4];
|
||||
|
||||
function square(number) {
|
||||
return number * number;
|
||||
}
|
||||
|
||||
*!*
|
||||
var squaredArr = arr.map(square);
|
||||
*/!*
|
||||
|
||||
alert(squaredArr); // получили массив квадратов чисел: 1, 4, 9, 16
|
||||
```
|
||||
|
||||
## every/some
|
||||
|
||||
Эти методы используется для проверки массива.
|
||||
|
||||
Метод ["arr.every(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every) возвращает `true`, если вызов `callback` вернёт `true` для *каждого* элемента `arr`.
|
||||
|
||||
|
||||
Метод ["arr.some(callback[, thisArg])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some) возвращает `true`, если вызов `callback` вернёт `true` для *какого-нибудь* элемента `arr`.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1, -1, 2, -2, 3];
|
||||
|
||||
function isPositive(number) {
|
||||
return number > 0;
|
||||
}
|
||||
|
||||
*!*
|
||||
alert( arr.every(isPositive) ); // false, не все положительные
|
||||
alert( arr.some(isPositive) ); // true, есть хоть одно положительное
|
||||
*/!*
|
||||
```
|
||||
|
||||
## reduce/reduceRight
|
||||
|
||||
Метод ["arr.reduce(callback[, initialValue])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce) используется для последовательной обработки каждого элемента массива с сохранением промежуточного результата.
|
||||
|
||||
Это один из самых сложных методов для работы с массивами. Но его стоит освоить, потому что временами с его помощью можно в несколько строк решить задачу, которая иначе потребовала бы в разы больше места и времени.
|
||||
|
||||
Метод `reduce` используется для вычисления на основе массива какого-либо единого значения, иначе говорят "для свёртки массива". Чуть далее мы разберём пример для вычисления суммы.
|
||||
|
||||
Он применяет функцию `callback` по очереди к каждому элементу массива слева направо, сохраняя при этом промежуточный результат.
|
||||
|
||||
Аргументы функции `callback(previousValue, currentItem, index, arr)`:
|
||||
|
||||
<ul>
|
||||
<li>`previousValue` -- последний результат вызова функции, он же "промежуточный результат". Значение `previousValue` при первом вызове равно `initialValue` (второй аргумент `reduce`) или, если у `reduce` нет второго аргумента, то оно равно первому элементу массива, а перебор начинается со второго.</li>
|
||||
<li>`currentItem` -- текущий элемент массива, элементы перебираются по очереди слева-направо. </li>
|
||||
<li>`index` -- номер текущего элемента.</li>
|
||||
<li>`arr` -- обрабатываемый массив.</li>
|
||||
</ul>
|
||||
|
||||
Разберём работу метода `reduce` на примере.
|
||||
|
||||
Пусть мы хотим вычислить сумму всех элементов массива. Можно сделать это при помощи цикла, но это как раз подходящий повод познакомиться с `reduce`.
|
||||
|
||||
Вот решение в одну строку:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1, 2, 3, 4, 5]
|
||||
|
||||
var result = arr.reduce(function(prev, current) { return prev + current }, 0);
|
||||
|
||||
alert(result); // 15
|
||||
```
|
||||
|
||||
Разберём, что в нём происходит.
|
||||
|
||||
Здесь начальное значение, с которого начинаются вычисления, равно нулю (второй аргумент `reduce`).
|
||||
|
||||
Сначала анонимная функция вызывается с этим начальным значением и первым элементом массива, результат запоминается и передаётся в следующий вызов, уже со вторым аргументом массива, затем новое значение участвует в вычислениях с третьим аргументом и так далее.
|
||||
|
||||
Таблица вычислений получается такая:
|
||||
<table class="bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>`prev`</th>
|
||||
<th>`current`</th>
|
||||
<th>результат</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>первый вызов</th>
|
||||
<td>`0`</td>
|
||||
<td>`1`</td>
|
||||
<td>`1`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>второй вызов</th>
|
||||
<td>`1`</td>
|
||||
<td>`2`</td>
|
||||
<td>`3`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>третий вызов</th>
|
||||
<td>`3`</td>
|
||||
<td>`3`</td>
|
||||
<td>`6`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>четвёртый вызов</th>
|
||||
<td>`6`</td>
|
||||
<td>`4`</td>
|
||||
<td>`10`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>пятый вызов</th>
|
||||
<td>`10`</td>
|
||||
<td>`5`</td>
|
||||
<td>`15`</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Функция-аргумент `reduce` могла бы также использовать параметры `i` и `array`, но здесь в них нет нужды.
|
||||
|
||||
**Можно сделать ещё короче!**
|
||||
|
||||
Посмотрим, что будет, если не указать `initialValue` в вызове `arr.reduce`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var arr = [1, 2, 3, 4, 5]
|
||||
|
||||
// убрали 0 в конце
|
||||
var result = arr.reduce(function(prev, current) { return prev + current });
|
||||
|
||||
alert(result); // 15
|
||||
```
|
||||
|
||||
Результат -- точно такой же! Это потому, что при отсутствии `initialValue` в качестве первого значения берётся первый элемент массива, а перебор стартует со второго.
|
||||
|
||||
Таблица вычислений будет такая же, за вычетом первой строки.
|
||||
|
||||
**Метод [arr.reduceRight](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduceRight) работает аналогично, но идёт по массиву справа-налево:**
|
||||
|
||||
|
||||
|
||||
## Итого
|
||||
|
||||
Мы рассмотрели методы:
|
||||
<ul>
|
||||
<li>`forEach` -- для *перебора* массива.</li>
|
||||
<li>`filter` -- для *фильтрации* массива.</li>
|
||||
<li>`every/some` -- для *проверки* массива.</li>
|
||||
<li>`map` -- для *трансформации* массива в массив.</li>
|
||||
<li>`reduce/reduceRight` -- для *прохода по массиву с вычислением значения*.</li>
|
||||
</ul>
|
||||
|
||||
Во многих ситуациях их использование позволяет написать код короче и понятнее, чем обычный перебор через `for`.
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue