Как в Javascript проверить, есть ли в массиве повторяющиеся значения?


95

Возможный дубликат:
самый простой способ найти повторяющиеся значения в массиве javascript

Как проверить, есть ли в массиве повторяющиеся значения?

Если некоторые элементы в массиве совпадают, вернуть true. В противном случае верните false.

['hello','goodbye','hey'] //return false because no duplicates exist
['hello','goodbye','hello'] // return true because duplicates exist

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



2
Я не хочу удалять список дубликатов. Я просто хочу знать истину или ложь, есть ли в списке дубликаты.
user847495

7
Этот вопрос не повторяется. Поскольку @ user847495 просто хочет проверить, существуют ли дубликаты, решение будет быстрее / проще, чем то, что необходимо для поиска всех вхождений дубликатов. Например, вы можете сделать это: codr.io/v/bvzxhqm
alden

2
с использованием подчеркивания , простой приемvar test=['hello','goodbye','hello'] ; if ( test.length != _.unique(test).length ) { // some code }
Сай Рам

4
Не дубликат отмеченного вопроса. Пожалуйста, обратите внимание, прежде чем отмечать вопросы как таковые.
Джон Вайс

Ответы:


222

Если у вас есть среда ES2015 (на момент написания: io.js, IE11, Chrome, Firefox, WebKit nightly), то следующее будет работать и будет быстро (а именно O (n)):

function hasDuplicates(array) {
    return (new Set(array)).size !== array.length;
}

Если вам нужны только строковые значения в массиве, будет работать следующее:

function hasDuplicates(array) {
    var valuesSoFar = Object.create(null);
    for (var i = 0; i < array.length; ++i) {
        var value = array[i];
        if (value in valuesSoFar) {
            return true;
        }
        valuesSoFar[value] = true;
    }
    return false;
}

Мы используем «хеш-таблицу» valuesSoFar, ключами которой являются значения, которые мы уже видели в массиве. Мы выполняем поиск, используя, inчтобы увидеть, было ли это значение уже обнаружено; если так, мы выходим из цикла и возвращаемся true.


Если вам нужна функция, которая работает не только со строковыми значениями, следующее будет работать, но не так эффективно; это O (n 2 ) вместо O (n).

function hasDuplicates(array) {
    var valuesSoFar = [];
    for (var i = 0; i < array.length; ++i) {
        var value = array[i];
        if (valuesSoFar.indexOf(value) !== -1) {
            return true;
        }
        valuesSoFar.push(value);
    }
    return false;
}

Разница просто в том, что мы используем массив вместо хеш-таблицы valuesSoFar, поскольку «хеш-таблицы» (то есть объекты) JavaScript имеют только строковые ключи. Это означает, что мы теряем время поиска O (1) in, вместо этого получаем время поиска O (n), равное indexOf.


3
О первом примере, который вы привели. Разве проверка не наоборот? Если ваша функция названа hasDuplicates, она должна проверить, действительно ли размер набора уменьшился в процессе его преобразования, верно? Следовательно, логический оператор должен быть, !==а не===
Тим Добеншютц 01

пожалуйста, отредактируйте. Я не могу редактировать, так как не меняю более 6 символов.
Tim Daubenschütz

1
Согласно MDN IE11 не поддерживает конструктор, использованный в первом примере
adam77

Обычная версия JS возвращается trueдля следующего массива:[1, '1']
Kunal

Таким образом, перед ответом «если вам нужны только строковые значения в массиве».
Доменик

4

Другой подход (также для элементов объекта / массива в массиве 1 ) может быть 2 :

function chkDuplicates(arr,justCheck){
  var len = arr.length, tmp = {}, arrtmp = arr.slice(), dupes = [];
  arrtmp.sort();
  while(len--){
   var val = arrtmp[len];
   if (/nul|nan|infini/i.test(String(val))){
     val = String(val);
    }
    if (tmp[JSON.stringify(val)]){
       if (justCheck) {return true;}
       dupes.push(val);
    }
    tmp[JSON.stringify(val)] = true;
  }
  return justCheck ? false : dupes.length ? dupes : null;
}
//usages
chkDuplicates([1,2,3,4,5],true);                           //=> false
chkDuplicates([1,2,3,4,5,9,10,5,1,2],true);                //=> true
chkDuplicates([{a:1,b:2},1,2,3,4,{a:1,b:2},[1,2,3]],true); //=> true
chkDuplicates([null,1,2,3,4,{a:1,b:2},NaN],true);          //=> false
chkDuplicates([1,2,3,4,5,1,2]);                            //=> [1,2]
chkDuplicates([1,2,3,4,5]);                                //=> null

Смотрите также...

1 нужен браузер, поддерживающий JSON, или библиотеку JSON, если нет.
2 edit: функция теперь может использоваться для простой проверки или для возврата массива повторяющихся значений


3
Проблемы, не связанные с showstopper, о которых следует знать: 1) изменяет исходный массив для сортировки; 2) не различает null, NaN, Infinity, +Infinity, и -Infinity; 3) объекты считаются равными, если они имеют одинаковые собственные свойства, даже если у них разные прототипы.
Доменик

1
@Domenic: да, надо было упомянуть об этом. Отредактировано, чтобы обойти изменение исходного массива.
KooiInc

@Domenic: исправлено на null / NaN / [+/-] Infinity, см. Правки.
KooiInc

@Domenic: Проблема 3) на самом деле не проблема для меня, потому что это именно то, что я хочу. Меня не волнует прототип, только ценности.
awe

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.