Введение — Что искать?
Прежде всего нужно ответить самому себе на вопрос, какой результат нужно считать успешным поиском. Давайте поясню, что я имею ввиду:
Поиск в массиве может:
- Искать значение элемента
- Искать значения элементов
- Искать индекс элемента
- Искать индексы элементов
В чём тут разница?
№ 0 — Искать элемент массива
В массиве могут быть не только примитивы, но и сложные объекты с разным уровнем вложенности.
[{a:'Вася'},{v:'Коля'},{r:'Дима'},{q:'Петя'},{g:'Дима'}]
Предположим, что мы хотим найти в этом массиве объектов такой ПЕРВЫЙ элемент, который содержит строку ‘Дима’. Причём мы хотим чтобы нам вернулся весь объект целиком. Как это сделать?
Нас в принципе интересует ЛЮБОЙ ОДИН объект из данного массива, а не все возможные.
Для этого нужно использовать метод find()
[{a:’Вася’},{v:’Коля’},{r:’Дима’},{q:’Петя’},{g:’Дима’}].find(i=>Object.values(i).includes(‘Дима’))
№ 1 — Искать значение элемента
Когда мы «ищем значение элемента», то по сути мы просто проверяем, существует ли в нашем массиве такое значение. Нам эту проверку нужно сделать всего один раз, до первого нахождения значения в элементе массива.
То есть когда алгоритм бежит по массиву и находит первое встречное нужное нам значение, то алгоритм просто возвращает нам ИСТИНУ (true). Мы как-бы убедились, что такое значение УЖЕ СУЩЕСТВУЕТ и можно делать другую часть задач.
Для такого варианта лучше всего подходит метод includes() для экземпляров класса Array.
var massiv = [11, 22, 33, 55, 66] massiv.includes(11) true massiv.includes(44) false massiv.includes(66) true
Пример из жизни
Вы строите одноэтажные дома. У вас есть база данных людей, которые заказывали у вас услугу строительства дома. К вам пришёл человек с жалобой на оказанную услугу спустя 15 лет. Вы знаете его ФИО. Вы пробегаете по массиву и сопоставляете ФИО. Вам нужно проверить в массиве человека.
Если этот человек действительно заказывал услугу у вас, то вам вернётся TRUE (истина). После этого вы можете предложить ему экспертизу.
Если этот человек НЕ заказывал услугу у вас, то вам вернётся FALSE (ложь). После этого вы можете предложить ему поискать документы, в которых указана другая строительная компания, а не ваша.
№ 2 — Искать значения элементов
Это тот случай в котором мы уже знаем, какое значение хотим найти в массиве, но нас больше всего интересует вопрос сколько таких значений присутствует в массиве? Мы хотим сосчитать количество повторений.
В этом нам поможет метод filter(), который возвращает новый массив элементов с отобранными значениями по условию. Когда мы получаем новый массив, то у него всегда можем узнать длину. Длина будет, как раз, тем самым количеством повторений.
var massiv = [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 8, 8]
massiv.filter(i=>i==5) [5, 5, 5]
massiv.filter(i=>i==5).length 3
Пример из жизни
У нас есть интернет-магазин. Мы продаём строительный крепёж (шурупы, болты, гвозди, гайки и т.п..). Есть список заказов.
Мы хотим понять сколько раз продавался товар. То есть нам нужно знать, как часто люди приобретают данный товар. Сопоставление подобных выборок поможет нам лучше формировать ассортимент магазина. Грубо говоря мы будем понимать популярность того или иного крепежа.
Если мы увидим, что за месяц товар был куплен 2 раза, а его на складе 500 кг, тогда нам нужно уменьшить закупаемое количество до 10 кг, чтобы не занимать место на складе, а освободить его для более популярной группы товаров.
Если мы увидим, что за месяц товар был куплен 122 раза, а его на складе 0 кг, тогда нам нужно увеличить закупаемое количество до 750 кг. Этот товар популярен.
№ 3 — Искать индекс элемента
Это тот случай, когда мы хотим подтвердить существование значения в массиве и получить индекс элемента, который первым встретится на пути. Знание индекса поможет нам взглянуть на значение.
С этой работой хорошо справляется метод findIndex().
var massiv = [15, 94, 124, 2343, 4, 5, 94, 112, 6, 84, 35463, 8]
massiv.findIndex(i=>i==94) 1
Пример из жизни
Мы в библиотеке. Нам нужна любая книга о муравьях. Мы делаем запрос в базу и получаем объект книги. Как это выглядит с технической стороны?
У нас есть несколько объектов книг (имитация базы данных):
var massiv = [ {название: "Кошки", автор:"Максим", текст: "иаптааа вававыаыа аваыв"}, {название: "Собаки", автор:"Иван", текст: "ывы авроаев выв ыв"}, {название: "Муравьи", автор:"Дима", текст: "ывфта ику ртоуцриар"}, {название: "Динозавры", автор:"Виктор", текст: "ыватогрм кур ывим"}, {название: "Муравьи", автор:"Иван", текст: "цпцр ацаар цвсровлс цлт"}, ]
В этом случае мы посылаем только часть информации в надежде получить всё остальное. Частью информации является запрос названия книги — «Муравьи».
massiv.findIndex(i=>i.название=="Муравьи") 2
В ответ нам приходит номер индекса первого подходящего элемента массива.
Но по факту само название книги или его индекс в базе данных нас мало интересует. Нам же нужен текст. Мы хотим получить информацию.
Теперь, зная индекс, мы можем получить весь объект из массива.
massiv[2] {название: "Муравьи", автор: "Дима", текст: "ывфта ику ртоуцриар"}
Теперь, владея объектом, мы можем получить текст данной книги.
massiv[2].текст "ывфта ику ртоуцриар"
Вы, наверное, обратили внимание, что мы получили только одну книгу о муравьях, хотя в нашей импровизированной базе была ещё одна книга с муравьиной тематикой другого автора.
Зачем мы так сделали? Почему одна а не все? Представьте, что у вас в базе данных лежат не книги, а разметка всех HTML-страниц сайтов в интернете. Вы хотите отыскать какую-то информацию, которая может встречаться на страницах в сети. Скорее всего под ваш запрос будет найдено огромное количество документов. Если вы захотите получить их все разом, то этот процесс может надолго затянуться и вы не увидите вообще ничего (просто устанете ждать).
Чтобы не нагружать базу данных лишними вычислениями и чтобы не ждать долго результата, как раз и нужен «одноразовый» метод findIndex(). Возможно первый вариант ответа вас полностью удовлетворит, тогда какой смысл «шерстить» всю базу данных.
Но в ряде случаев одним результатом не обойтись, читайте далее.
№ 4 — Искать индексы элементов
Этот вариант поиска предполагает возврат индексов элементов массива, которые соответствуют заданному условию отбора. То есть мы хотим точно знать под каким индексом находится каждый элемент, подходящий под условие. Для решения этой задачи нам нужно использовать метод entries() для объектов-прототипов Array.
Метод entries() пробегает по массиву и возвращает итератор массива, в котором при обходе будут «вытащены» индексы. (По умолчанию мы не видим индексов массивов). Для «вытаскивания» индексов из итератора нам нужно передать его в метод from() конструктора Array. Либо использовать оператор спред «…»
var massiv = [1, 3, 5, 3, 3, 5, 1, 1, 6, 7, 5, 9, 0, 6, 7, 5]
Например, мы хотим получить индексы элементов со значениями 5. Как это сделать?
Array.from(massiv.entries()).filter(i=>i[1]==5).map(i=>i[0]) или [...massiv.entries()].filter(i=>i[1]==5).map(i=>i[0])
В обоих случаях мы получим индексы элементов
[2, 5, 10, 15]
Другой пример. Есть счета, люди и их деньги на счетах в разных банках. Нужно узнать какие суммы хранит Петя в банках? До запроса мы не знаем какие суммы хранит Петя, мы лишь знаем что он Петя и всё.
var worker = [ {name: "Петя", money:10}, {name: "Вася", money:20}, {name: "Дима", money:30}, {name: "Петя", money:5}, {name: "Петя", money:2}, {name: "Дима", money:15}, ]
Выполним сбор информации о счетах Пети:
[...worker.entries()].filter(i=>i[1].name=="Петя").map(i=>i[0]) [0, 3, 4]
В базе данных счетов под индексами 0, 3 и 4 будут лежать суммы. Их можно будет достать по отдельности, например:
worker[0].money 10 worker[3].money 5 worker[4].money 2
Сейчас мы знаем какие суммы хранит Петя и на каких счетах. Если Петя «накосячит» по жизни, то теперь его в любой момент можно легко поставить на место. Например можно обнулить его счета.
worker[0].money = 0 worker[3].money = 0 worker[4].money = 0
У Пети больше нет денег — Петю «Обнулили». Это был показательный пример того, зачем нужно собирать индексы элементов массива по заданным условиям. Если знаешь индекс массиве, то можешь поменять значение под ним.
Пример из жизни
Мы производим автомобили. В цехах работают роботы-сборщики. Люди только смотрят в мониторы — следят за общим процессом. Дилеры стали возвращать нам нашу продукцию по рекламации. Конечные покупатели стали слышать стук в двигателе после 2000 км пробега. Мы собрали данные о 25000 автомобилей от дилеров и принимаем решение отозвать автомобили, для устранения неисправности.
Мы не можем с ходу выявить причину повреждений, но мы уже знаем тип станка, который допускает производственный дефект. Проблема только в одном. Таких станков у нас 6 штук.
Мы делаем выборки в массиве по станкам и понимаем, что 21000 автомобилей работали с деталью станка № 4, 3000 авто с № 3 и 1000 авто с № 5. Мы почти на 100% уверены, что проблему нужно искать у станка № 4.
Мы собираем инженеров и конструкторов и идём в производственный цех. Мы смотрим на потолок, а оттуда капает вода прямо на станок № 4. Некоторые брызги затрагивают станок № 5. А под станком № 3 образовалась огромная лужа. Мы выявляем неисправность и благодарим JavaScript программиста, который написал алгоритм поиска дефектного станка.
Информационные ссылки
Стандарт ECMAScript — Раздел «23.1.3.8 Array.prototype.find ( predicate [ , thisArg ] )» — https://tc39.es/ecma262/#sec-array.prototype.find
Стандарт ECMAScript — Раздел «23.1.3.9 Array.prototype.findIndex ( predicate [ , thisArg ] )» — https://tc39.es/ecma262/#sec-array.prototype.findindex
Стандарт ECMAScript — Раздел «23.1.3.7 Array.prototype.filter ( callbackfn [ , thisArg ] )» — https://tc39.es/ecma262/#sec-array.prototype.filter
Стандарт ECMAScript — Раздел «23.1.3.4 Array.prototype.entries ( )» — https://tc39.es/ecma262/#sec-array.prototype.entries