Поиск самой длинной строки в массиве JavaScript — полезная операция для определения необходимого места для отображения данных. В этой статье мы проанализируем все возможные решения и сравним их по удобочитаемости, скорости и памяти. Например, я постоянно делаю это в своей библиотеке диаграмм, чтобы выделить место для делений осей y/x.
Обзор задач
Учитывая массив значений, найдите самое длинное (строковое) значение в массиве.
Дан массив: [1, 10, 'longest string', false, ['this', 'may', 'be', 'long', 'enough;], { prop: 'value' }, 'short string', null, undefined]
.
Ожидаемый результат: longest string
.
Теория
документация MDN Object.prototype.toString()
Существует два способа преобразования любого объекта в строку. Давайте изучим их.
«Все есть объект»
Ну, на самом деле, нет.
Есть 7 примитивов: строка, число, bigint, логическое значение, неопределенный, ноль, символ. Каждый примитив не является объектом, хотя каждый примитив имеет оболочку объекта. Мы не можем преобразовывать непримитивные объекты, скажем, в настоящую строку, означающую значения, которые мы, люди, можем рассматривать как строки.
Какие данные считать возможными для преобразования в строки
Я бы сказал, что такие задачи могут нуждаться в дополнительных деталях для рассмотрения, но для данной задачи допустим, что мы хотим сравнить только примитивы. Но поскольку null
или undefined
означают, что переменная не имеет значения, мы будем рассматривать только значения string
, number
, bigint
и boolean
. Каждый symbol
уникален и не является счетным, поэтому эти значения тоже рассматривать не будем (подробнее о примитиве Symbol
здесь).
Все примитивы, которые мы рассматриваем как «настоящие» строки, имеют собственный метод toString
, который интерпретирует значение как строку.
Как преобразовать в строку?
Вызов метода toString
Просто как тот. Просто вызовите variable.toString()
и получите строковое представление.
Вызов конструктора String()
Напишите String(variable)
и получите строковое представление. Использование конструктора String
примерно так же, как вызов метода toString
. По крайней мере, на избранных примитивах.
Конкатенация строк с помощью оператора присваивания «+»
Несмотря на то, что существует метод String.prorotype.concat()
, документы MDN говорят использовать операторы + или += для объединения строк из-за соображений производительности.
Вызов '' + variable
даст тот же результат, что и вызов ''.concat(variable)
, который преобразует variable
в String
, а затем объединяет его с пустой строкой.
Итерация по массиву
Существует 5 способов перебора массива:
Давайте попробуем их и посмотрим, как они работают.
Поиск самого длинного (строкового) значения в массиве
Для наших операций мы рассмотрим:
const arr = [1, 10, 'longest string', false, ['this', 'may', 'be', 'long', 'enough;], { prop: 'value' }, 'short string', null, undefine];
const arrLength = arr.length;
const primitives = [ 'string', 'number', 'bigint', 'boolean' ]; let longestLength = 0; let longestValue = null;
Для цикла
for (let i = 0; i < arrLength; i++) { const value = arr[i]; if (primitives.includes(typeof value)) { const valueLength = value.toString().length; if (valueLength > longestLength) { longestLength = valueLength; longestValue = value; } } }
Для _ цикла
for (const value of arr) { if (primitives.includes(typeof value)) { const valueLength = value.toString().length; if (valueLength > longestLength) { longestLength = valueLength; longestValue = value; } } }
метод foreach()
arr.forEach(value => { if (primitives.includes(typeof value)) { const valueLength = value.toString().length; if (valueLength > longestLength) { longestLength = valueLength; longestValue = value; } } });
метод карты()
arr.map(value => { if (primitives.includes(typeof value)) { const valueLength = value.toString().length; if (valueLength > longestLength) { longestLength = valueLength; longestValue = value; } } });
метод уменьшения()
arr.reduce((previousValue, currentValue) => { if (primitives.includes(typeof currentValue)) { const valueLength = currentValue.toString().length; if (valueLength > longestLength) { longestLength = valueLength; previousValue = currentValue; } } }, longestLength);
Анализ
Как мы видим, все циклы в основном выполняют одну и ту же операцию при условии. Кроме того, просто взглянув на код, становится ясно, что последние 2 метода (map()
и reduce()
) являются накладными. Но мы все равно будем учитывать их в наших тестах.
Производительность
Давайте перейдем на https://jsben.ch/ и создадим несколько тестов.
1к записей
Как и ожидалось, простой цикл for
работает лучше, чем другие методы, причем map
является медленным.
Бенчмарк доступен здесь: https://jsben.ch/APBhX
1 млн записей
Для этого теста цикл for
по-прежнему является лучшим выбором, а методы reduce
и forEach
занимают второе место.
Бенчмарк доступен здесь: https://jsben.ch/Cu9H2
Заключение
В данном случае использование простого и надежного цикла for
является лучшим выбором, так как читабельность кода остается такой же, как и при использовании других методов, но скорость является самой высокой.
Спасибо за прочтение,
kyoshie
Читать далее: