3.1. Линейный («обычный») поиск
Найти что-то в массиве — довольно частая задача. Это может быть поиск целого объекта по его признаку: например, найти полный объект банковской карточки из списка сохранённых, зная только её id/номер. Или просто проверка на вхождение: к примеру, чтобы узнать, можно ли показывать определённый контент пользователю, можно проверять его права в системе в массиве разрешающих просмотр прав.
Самый простой и распространённый способ поиска в массивах и других коллекциях — линейный поиск. Это довольно «глупый» алгоритм, который просто перебирает все элементы до тех пор, пока не встретит нужный нам или не дойдёт до конца массива. Например, у нас есть массив из запрещённых для постов слов: ['Спотти', 'Персик', 'котик']
. И нам надо проверить, запрещено ли слово 'Кекс'
. Сначала мы посмотрим на 'Спотти'
и сравним его с искомым словом. Они не равны, поэтому двигаемся дальше — к слову 'Персик'
. С ним и с 'котик'
-ом ситуация такая же: сравнение их с 'Кекс'
-ом вернёт нам false
. А затем мы придём в конец массива. Это значит, искомого элемента в нём нет, можно постить! Алгоритмическую сложность подобных алгоритмов, которые перебирают все элементы из массива, мы уже знаем — это O(n)
. (А сколько займёт прогон через такой список запрещённых слов поста из m
слов?)
Линейный поиск не самый оптимальный алгоритм, но он позволяет работать вообще с любыми коллекциями. Ведь всё и везде можно найти, просто просмотрев все возможные элементы!
В JavaScript есть несколько способов нахождения искомого в массивах. Уверены, вы пользовались всеми или почти всеми из них, но давайте их вспомним.
Проверка на вхождение с помощью includes
Если элемент у нас уже есть и нам надо только проверить, есть ли он в массиве, стоит использовать includes
. Пример сверху можно переписать вот так:
const forbiddenWords = ['Спотти', 'Персик', 'котик'];
function checkIfForbidden(word) {
return forbiddenWords.includes(word);
}
checkIfForbidden('Кекс'); // false
Поиск одного элемента с find или нескольких — с filter
Например, если у нас есть список зарегистрированных на мероприятие участников:
const participants = [
{
id: 1,
name: 'Иван Иванов',
meal: 'regular', // Предпочтения в еде, либо веган, либо нет
},
{
id: 2,
name: 'Игорь Николаев',
meal: 'vegan',
},
{
id: 3,
name: 'Павел Константинов',
meal: 'regular',
}
]
И мы хотим достать оттуда одного «целого» участника, зная только его id, то наш выбор — find
. Он вернёт только первый элемент, который подходит под наше условие:
const firstParticipant = participants.find(({id}) => id === 1);
А если нам нужно достать несколько участников, например, всех веганов, то нужно использовать filter
:
const vegans = participants.filter(({meal}) => meal === 'vegan');
Поиск индекса элемента в массиве с помощью findIndex и indexOf
Бывают случаи, когда нам нужен не сам элемент массива, а только его индекс. Например, чтобы удалить его потом из массива по найденному индексу. findIndex
работает, как и find
: принимает аргументом функцию для поиска (её ещё называют «предикат») и возвращает индекс первого найденного элемента или -1, если такого не нашлось.
const pashaIndex = participants.findIndex(({name}) => name === 'Павел Константинов'); // 2
А indexOf
принимает аргументом уже сам элемент, а не предикат, и также возвращает либо его индекс, либо -1, если его нет внутри.
const firstIndex = participants.indexOf(firstParticipant);