Love Frontend
Сообщество
фронтенд разработчиков
EN

Решения задачи на поиск уникального значения.

Дата публикации: 06.07.2019

Даётся массив чисел неопределённой длины, среди которого есть одно уникальное число.

Пример:         findUniq([ 1, 1, 1, 2, 1, 1 ]) === 2 // true
findUniq([ 0, 0.25, 0, 0, 0 ]) === 0.25 // true

Задача довольно тривиальна, но её можно интересно решить на JS. Для тех, кто хочет подумать сам, вот ссылка на задачу в codewars, она идёт 1-й в комплекте аналогичных задач, другие 2 посложнее

Задачу можно решить топорно с отдельным массивом для буфера, можно решить поинтереснее если сначала отсортировать массив. Например, отсортируем в порядке возрастания первый массив из примера:

           [ 1, 1, 1, 2, 1].sort((a, b) => a -b)
// [ 1, 1, 1, 1, 2]

Если у нас было бы наоборот, что много цифр 2 и только одна 1, то тогда у нас первое число было бы уникальное, а затем все остальные числа просто повторялись бы.

           [ 2, 2, 1, 2, 2].sort((a, b) => a -b)
// [ 1, 2, 2, 2, 2]

Значит нам нужно просто возвращать первое число, если оно не равно следующему или же последнее, если первое равно второму. В итоге наше решение примет следующий вид:

             function findUniq(arr) {
arr.sort((a, b) => a -b)
return arr[0] === arr[1] ? arr.pop() : arr[0]
}

Есть, на мой взгляд, ещё более интересное и достойное решение. Использование методов прототипа массивов indexOf() и lastIndexOf()

Дело в том, что одно уникальное значение в массиве должно находиться только по одному индексу массива. То есть если мы найдём первое положение элемента начиная сначала массива и найдём его индекс, начиная с конца (то есть последний индекс), то это должен быть один и тот же индекс. У повторяющегося элемента индекс от начала массива и от конца всегда будет разный:

let arr = [ 5, 7, 5, 5, 5]
arr.indexOf(5) // 0
arr.lastIndexOf(5) // 4
Первый индекс числа 5 = 0, а последний = 4
let arr = [ 5, 7, 5, 5, 5]
arr.indexOf(7) // 1
arr.lastIndexOf(7) // 1
Первый и последний индексы совпадают. Число уникальное.

Додумавшись до этого интересного свойства уникального элемента, можно прийти к финальному решению и найти элемент массива, который имеет равный первый и последний индекс, с помощью метода find()

function findUniq(arr) {
return arr.find(n => arr.indexOf(n) === arr.lastIndexOf(n))
}

На мой взгляд очень интересное решение и реализация умещается в одну строку, сравните например с кодом функции _.uniq() из библиотеки Lodash, которое занимает более 70 строк и при этом тянет ещё другие функции. Однако не стоит забывать, что там используется механизм сравнения SameValueZero

Но в целом, если вам для задачи нужно просто найти уникальное число или строку без сравнения NaN, то можете смело писать такую функцию сами. Алгоритмы сравнения в Array.prototype.indexOf и Array.prototype.lastIndexOf используют строгое равенство для сравнения ===, а SameValueZero алгоритм работает точно так же, за исключением того, что возвращает true если сравниваются два NaN, в то время как NaN === NaN вернёт false

Оставьте свой e-mail чтобы получать уведомления о свежих статьях.