Типовые алгоритмы с массивами на JavaScript: решаем задачи одной строчкой кода
Часто мы по инерции пишем типовые алгоритмы на JavaScript как на классическом Си или Паскале, то есть, с "ручной" организацией циклов и проверкой свойств.
Меж тем, писать надо скорее как на (хорошем новом) PHP или C++ с библиотекой алгоритмов, применяя готовые функции языка для работы с массивами и контейнерами.
Уже есть в блоге по теме: сортировка числового массива на JavaScript, функция array_unique (оставить только уникальные элементы) на JavaScript, матрица на JavaScript.
Вывод всех примеров делается просто в консоль браузера.
Узнать, является ли объект массивом
<script> let arr = [ 1, 2, 3 ]; let val = 0; let obj = { index: 0, value: "val" }; console.log(Array.isArray(arr)); // true console.log(Array.isArray(val)); // false console.log(Array.isArray(obj)); // false </script>
Заполнить массив повторяющимися значениями
<script> let arr = Array(5).fill(0); console.log(arr); // [ 0, 0, 0, 0, 0 ] </script>
Если нужно заполнение значениями 1,2,...,N
, тогда так:
<script> const n = 5; let arr = Array(n).fill(0).map(function(val,index){return index+1;}); console.log(arr); // [ 1, 2, 3, 4, 5 ] </script>
Если массив двумерный, то есть, матрица, потребуется код вида
let arr = Array(2).fill(0).map(() => {return Array(3).fill(0)}); console.log (arr); //матрица 2x3 из нулей
а не просто
let arr = Array(2).fill(Array(3).fill(0));
для последующего правильного присваивания значений элементам этой матрицы.
Задать массив n случайных целых чисел из диапазона [n1;n2]
<script> const n = 10, n1 = -5, n2 = 5; let arr = []; arr = Array(n).fill(0).map(function(){return Math.floor(n1+Math.random()*(n2-n1+1));}); console.log(arr); </script>
Скопировать массив в другой массив
<script> let arr = [1,2,3,4,5]; let arr2 = arr.slice(); console.log(arr2); //[ 1, 2, 3, 4, 5 ] </script>
Скопировать часть элементов массива на новые позиции (затирая предыдущие элементы)
<script> let arr = [1,2,3,4,5]; let target=3,start=0,end=2; arr.copyWithin(target,start,end); console.log(arr); // [ 1, 2, 3, 1, 2 ] </script>
Найти сумму элементов массива
<script> let arr = [1,2,3,4]; let sum = arr.reduce((a, b) => a + b, 0); console.log(sum); //10 </script>
Вычислить какую-либо другую характеристику массива
<script> let arr = [ 1, 2, 3, 0, 5 ]; let prod = arr.reduce((prod, val) => (val == 0 ? prod : prod*val), 1); console.log("Произведение ненулеых элементов = "+prod); // Произведение ненулеых элементов = 30 </script>
Функция reduce
применяется по очереди ко всем элементам массива и "переносит" свой результат на следующий вызов.
Аргумент prod
означает предыдущее значение функции, а val
- очередной элемент массива. Лучше использовать стрелочные функции, но если с ними непонятно, можно и так:
<script> let arr = [ 1, 2, 3, 0, 5 ]; let prod = arr.reduce( function(previousValue, item, index) { return (item == 0 ? previousValue : previousValue*item); }, 1 ); console.log(prod); // 30 </script>
Метод reduceRight()
аналогично применяет функцию к аккумулятору и каждому значению массива, сканируя последний справа налево.
Найти максимум или минимум в массиве
Можно как выше, а можно и по-другому.
<script> let arr = [2,4,3,1]; let max = Math.max.apply(null, arr); let min = Math.min.apply(null, arr); console.log(min+' '+max); //1 4 </script>
Не рекомендуется применять этот подход для больших размерностей.
Узнать, если ли в массиве повторяющиеся элементы
<script> let arr1 = [2,4,3,1]; let dup1 = (new Set(arr1)).size !== arr1.length; console.log(dup1); //false let arr2 = ['s1','s2','s1','s4']; let dup2 = (new Set(arr2)).size !== arr2.length; console.log(dup2); //true </script>
Узнать, есть ли в массиве некоторое значение
<script> let arr = [2,4,3,1,2,1]; let c = arr.includes(5); console.log(c); //false </script>
Если ищем массив в массиве массивов, тогда так:
<script> function includesArray (arr, val) { //Есть ли массив val в массиве массивов arr //просто includes для массива массивов не подойдет arr = JSON.stringify(arr); val = JSON.stringify(val); return arr.indexOf(val) != -1; } let arr = [ [1,2], [3,4], [5,6] ]; let val = [5,6]; console.log (includesArray(arr, val)); //true console.log (includesArray(arr, [6,5])); //false </script>
Найти индекс первого вхождения значения в массив
<script> let arr = [ 1, 2, 3, 4, 2 ]; let cnt = 0; let n = arr.indexOf (2); console.log(n); // 1 </script>
Найти индекс последнего вхождения значения в массив
<script> let arr = [ 1, 2, 3, 4, 2 ]; let cnt = 0; let n = arr.lastIndexOf (2); console.log(n); // 4 </script>
Если ничего не найдено, этот и предыдущий методы вернут -1.
Подсчитать количество вхождений значения в массив
<script> let arr = [2,4,3,1,2,1]; let val = 1; let n = arr.filter(function(x){return x==val}).length; console.log(n); //2 </script>
Удалить из массива элемент или несколько элементов, начиная с нужного индекса
<script> let arr = [1,2,3,4,5]; arr.splice(1,2); //индекс, количество console.log(arr); // [ 1, 4, 5 ] </script>
А если нужно заменить удаляемые элементы другими?
<script> let arr = [1,2,3,4,5]; arr.splice(1,2,10,10); console.log(arr); // [ 1, 10, 10, 4, 5 ] </script>
Вставить в массив элементы, начиная с индекса n
<script> let arr = [1,2,3,4,5]; let n = 2; arr.splice(n,0,10,11); console.log(arr); // [ 1, 2, 10, 11, 3, 4, 5 ] </script>
Вырезать из массива подмассив элементов с индексами от n1 до n2
<script> let arr = [1,2,3,4,5]; let n1 = 1, n2 = 3; let arr2 = arr.slice(n1,n2); console.log(arr2); // [ 2, 3 ] </script>
Соединить массивы или массивы и дополнительные элементы
<script> let arr1 = [1,2]; let arr2 = [4,5]; let arr = []; arr = arr.concat(arr1,3,arr2); console.log(arr); // [ 1, 2, 3, 4, 5 ] </script>
Преобразовать массив в строку без разделителя между элементами
<script> let arr = [1,2,3,4,5]; let s = arr.join(''); console.log(s); // 12345 </script>
Преобразовать массив в строку с элементами, разделёнными нужным разделителем
<script> let arr = [1,2,3,4,5]; let s = arr.join(';'); console.log(s); // 1;2;3;4;5 </script>
Преобразовать строку в массив элементов, разбивая её по нужному символу
<script> let s = '1;2;3;4;5;;' let arr = s.split(';'); console.log(arr); // [ "1", "2", "3", "4", "5", "", "" ] </script>
Здесь получится массив строк, а если нужен именно массив чисел из исходной строки, то
<script> let str = "0.07,-0.15,0.28,0.26,0.24,0"; let arr = str.split(',').map(Number); console.log (arr); // массив чисел </script>
Выполнить некую функцию для каждого элемента массива
<script> let arr = [ 1, 2, 3, 4, 5 ]; let cnt = 0; arr.forEach(function(item, index) { if (item%2) cnt++; }); console.log("Количество нечётных элементов в массиве = "+cnt); //Количество нечётных элементов в массиве = 3 </script>
Выполнить некую функцию для каждого элемента массива и вернуть массив результатов выполнения этой функции
<script> let arr = [ 1, -2, -3, 4, 5 ]; let arr2 = arr.map(function(item, index) { return item<0 ? 0 : item; }); console.log(arr2); // [ 1, 0, 0, 4, 5 ] </script>
То есть, можно, например, сделать замену элементов по какому-то правилу.
Выполнить некую функцию для каждого элемента массива и проверить, есть ли хотя бы один истинный результат вызова функции
<script> let arr = [ 1, 2, 3, 4, 5 ]; let arr2 = arr.some(function(item,index){return item>10;}); console.log(arr2); // false </script>
Выполнить некую функцию для каждого элемента массива и проверить, истинны ли все результаты вызова функции
<script> let arr = [ 1, 2, 3, 4, 5 ]; let res = arr.every(function(item,index){return item<10;}); console.log(res); // true </script>
Найти в массиве объектов первый объект, отвечающий условию
<script> let users = [ {id: 1, name: "Вася"}, {id: 2, name: "Петя"}, {id: 3, name: "Маша"} ]; let user = users.find(item => item.id == 1); console.log(user); // Object { id: 1, name: "Вася" } </script>
Если ничего не найдено, результат будет undefined
Найти в массиве объектов индекс первого объекта, отвечающего условию
<script> let users = [ {id: 1, name: "Вася"}, {id: 2, name: "Петя"}, {id: 3, name: "Маша"} ]; let user = users.findIndex(item => item.id == 2); console.log(user); // 1 </script>
Если ничего не найдено, результат будет -1
Перевернуть массив
<script> let arr = [ 1, 2, 3, 4, 5 ]; arr.reverse(); console.log(arr); // [ 5, 4, 3, 2, 1 ] </script>
Отфильтровать массив (оставить элементы, отвечающие нужному условию или условиям)
Удобнее всего - стандартный метод filter
со стрелочной функцией обратного вызова в качестве аргумента. Аргумент x
самой функции означает очередной элемент массива. Если функция вернёт true
, элемент исходного массива добавляется в преобразованный массив, который и будет результатом вызова функции filter
.
<script> let arr = [5, 4, 3, 8, 0]; let a = 3, b = 5; let filtered = arr.filter (x => x>=a && x<=b); //элементы из интервала [3, 5] console.log (filtered); // [5, 4, 3] </script>
<script> let arr = [1, 0, -2, -1, 3]; let filtered = arr.filter (x => x>0); //положительные элементы console.log (filtered); // [1, 3] </script>
Итого и другие простые методы массивов
Все методы вызываются через точку после имени массива, ...items
означает, что аргументов может быть несколько.
Для добавления/удаления элементов:
unshift(...items)
– добавляет элементы в начало;shift()
– извлекает элемент из начала;push (...items)
– добавляет элементы в конец;pop()
– извлекает элемент с конца.splice(pos, deleteCount, ...items)
– начиная с индексаpos
, удаляетdeleteCount
элементов и вставляетitems
;slice(start, end)
– создаёт новый массив, копируя в него элементы с позицииstart
доend
(не включаяend
);fill(value, start, end)
- позволяет заполнить массив нужным значением;copyWithin(target,start,end)
- переписывает часть элементов внутри массива;concat(...items)
– возвращает новый массив: копирует все члены текущего массива и добавляет к немуitems
. Если какой-то изitems
является массивом, тогда берутся его элементы.
Для поиска среди элементов:
indexOf / lastIndexOf(item, pos)
– ищетitem
, начиная с позицииpos
, и возвращает его индекс или-1
, если ничего не найдено;includes(value)
– возвращаетtrue
, если в массиве имеется элементvalue
, в противном случаеfalse
;find(func)
/filter(func)
– фильтрует элементы через функцию и отдаёт первое/все значения, при прохождении которых через функцию возвращаетсяtrue
;findIndex(func)
похож наfind
, но возвращает индекс вместо значения;some(func)
/every(func)
- проверяют, выполняется ли некоторое свойство хотя бы для одного / для всех элементов массива.
Для перебора элементов:
Array.isArray(arr)
- проверяет, является лиarr
массивом;forEach(func)
– вызываетfunc
для каждого элемента. Ничего не возвращает.
Для преобразования массива:
map(func)
– создаёт новый массив из результатов вызоваfunc
для каждого элемента;sort(func)
– сортирует массив "на месте", а потом возвращает его;reverse()
– "на месте" меняет порядок следования элементов на противоположный и возвращает изменённый массив;split(div)
/join(div)
– преобразуют строку в массив и обратно, применяя разделительdiv
;reduce(func, initial)
– вычисляет одно значение на основе всего массива, вызываяfunc
для каждого элемента и передавая промежуточный результат между вызовами.
Обратите внимание, что ряд методов (sort
, reverse
, splice
, copyWithin
) изменяют исходный массив.
Этих методов обычно достаточно для удобной работы с массивами.
Всё о массивах в JavaScript от Mozilla
22.02.2020, 11:05 [10967 просмотров]