Получить все неуникальные значения (т.е. дубликаты / более одного вхождения) в массиве - PullRequest
370 голосов
/ 08 мая 2009

Мне нужно проверить массив JavaScript, чтобы увидеть, есть ли какие-либо повторяющиеся значения. Какой самый простой способ сделать это? Мне просто нужно выяснить, что такое дублированные значения - мне не нужны их индексы или сколько раз они дублируются.

Я знаю, что могу перебрать массив и проверить все остальные значения на совпадение, но, похоже, должен быть более простой способ. Есть идеи? Спасибо!

Подобный вопрос:

Ответы [ 73 ]

265 голосов
/ 08 мая 2009

Вы можете отсортировать массив, а затем запустить его и посмотреть, совпадает ли следующий (или предыдущий) индекс с текущим. Предполагая, что ваш алгоритм сортировки хорош, он должен быть меньше, чем O (n 2 ):

var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7];
var sorted_arr = arr.slice().sort(); // You can define the comparing function here. 
                                     // JS by default uses a crappy string compare.
                                     // (we use slice to clone the array so the
                                     // original array won't be modified)
var results = [];
for (var i = 0; i < sorted_arr.length - 1; i++) {
    if (sorted_arr[i + 1] == sorted_arr[i]) {
        results.push(sorted_arr[i]);
    }
}

console.log(results);
203 голосов
/ 08 мая 2009

Если вы хотите выявить дубликаты, попробуйте это отличное решение:

function eliminateDuplicates(arr) {
  var i,
      len = arr.length,
      out = [],
      obj = {};

  for (i = 0; i < len; i++) {
    obj[arr[i]] = 0;
  }
  for (i in obj) {
    out.push(i);
  }
  return out;
}

Источник: http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/

151 голосов
/ 26 июля 2014

Это мой ответ из дубликата темы (!):

При написании этой записи 2014 - все примеры были для for-loop или jQuery. Javascript имеет идеальные инструменты для этого: сортировать, отображать и уменьшать.

Найти дубликаты

var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']

var uniq = names
  .map((name) => {
    return {
      count: 1,
      name: name
    }
  })
  .reduce((a, b) => {
    a[b.name] = (a[b.name] || 0) + b.count
    return a
  }, {})

var duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1)

console.log(duplicates) // [ 'Nancy' ]

Более функциональный синтаксис:

@ Дмитрий-Лаптин указал, что необходимо удалить код. Это более компактная версия того же кода. Использование некоторых трюков ES6 и функций высшего порядка:

const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']

const count = names =>
  names.reduce((a, b) => ({ ...a,
    [b]: (a[b] || 0) + 1
  }), {}) // don't forget to initialize the accumulator

const duplicates = dict =>
  Object.keys(dict).filter((a) => dict[a] > 1)

console.log(count(names)) // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 }
console.log(duplicates(count(names))) // [ 'Nancy' ]
43 голосов
/ 10 марта 2016

Найти повторяющиеся значения в массиве

Это должен быть один из самых коротких способов найти дублирующиеся значения в массиве. Как специально запрашивается OP, это не удаляет дубликаты, а находит их .

var input = [1, 2, 3, 1, 3, 1];

var duplicates = input.reduce(function(acc, el, i, arr) {
  if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);

document.write(duplicates); // = 1,3 (actual array == [1, 3])

Это не требует сортировки или каких-либо сторонних фреймворков. Это также не нуждается в ручных петлях. Он работает с каждым значением indexOf () (или, чтобы быть более понятным: оператор строгого сравнения ) поддерживает.

Из-за lower () и indexOf () требуется как минимум IE 9.

29 голосов
/ 08 мая 2009

Вы можете добавить эту функцию или настроить ее и добавить в прототип Javascript Array:

Array.prototype.unique = function () {
    var r = new Array();
    o:for(var i = 0, n = this.length; i < n; i++)
    {
        for(var x = 0, y = r.length; x < y; x++)
        {
            if(r[x]==this[i])
            {
                alert('this is a DUPE!');
                continue o;
            }
        }
        r[r.length] = this[i];
    }
    return r;
}

var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9];
var unique = arr.unique();
alert(unique);
27 голосов
/ 28 октября 2011

ОБНОВЛЕНО: ниже используется оптимизированная комбинированная стратегия. Он оптимизирует поиск примитивов, чтобы извлечь выгоду из времени поиска по хэшу O (1) (для массива примитивов unique - O (n)). Поиск объектов оптимизируется путем тегирования объектов с уникальным идентификатором при выполнении итерации, поэтому идентификация дублированных объектов также составляет O (1) для каждого элемента и O (n) для всего списка. Единственное исключение - это замороженные элементы, но они редки, и резерв предоставляется с использованием массива и indexOf.

var unique = function(){
  var hasOwn = {}.hasOwnProperty,
      toString = {}.toString,
      uids = {};

  function uid(){
    var key = Math.random().toString(36).slice(2);
    return key in uids ? uid() : uids[key] = key;
  }

  function unique(array){
    var strings = {}, numbers = {}, others = {},
        tagged = [], failed = [],
        count = 0, i = array.length,
        item, type;

    var id = uid();

    while (i--) {
      item = array[i];
      type = typeof item;
      if (item == null || type !== 'object' && type !== 'function') {
        // primitive
        switch (type) {
          case 'string': strings[item] = true; break;
          case 'number': numbers[item] = true; break;
          default: others[item] = item; break;
        }
      } else {
        // object
        if (!hasOwn.call(item, id)) {
          try {
            item[id] = true;
            tagged[count++] = item;
          } catch (e){
            if (failed.indexOf(item) === -1)
              failed[failed.length] = item;
          }
        }
      }
    }

    // remove the tags
    while (count--)
      delete tagged[count][id];

    tagged = tagged.concat(failed);
    count = tagged.length;

    // append primitives to results
    for (i in strings)
      if (hasOwn.call(strings, i))
        tagged[count++] = i;

    for (i in numbers)
      if (hasOwn.call(numbers, i))
        tagged[count++] = +i;

    for (i in others)
      if (hasOwn.call(others, i))
        tagged[count++] = others[i];

    return tagged;
  }

  return unique;
}();

Если у вас есть доступные коллекции ES6, то существует гораздо более простая и значительно более быстрая версия. (шим для IE9 + и других браузеров здесь: https://github.com/Benvie/ES6-Harmony-Collections-Shim)

function unique(array){
  var seen = new Set;
  return array.filter(function(item){
    if (!seen.has(item)) {
      seen.add(item);
      return true;
    }
  });
}
17 голосов
/ 24 июня 2015
var a = ["a","a","b","c","c"];

a.filter(function(value,index,self){ return (self.indexOf(value) !== index )})
17 голосов
/ 09 мая 2009

Это должно дать вам то, что вы хотите, только дубликаты.

function find_duplicates(arr) {
  var len=arr.length,
      out=[],
      counts={};

  for (var i=0;i<len;i++) {
    var item = arr[i];
    counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
    if (counts[item] === 2) {
      out.push(item);
    }
  }

  return out;
}

find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order.
13 голосов
/ 04 сентября 2012

с использованием underscore.js

function hasDuplicate(arr){
    return (arr.length != _.uniq(arr).length);
}
6 голосов
/ 20 августа 2015

Когда все, что вам нужно, это проверить, что нет дубликатов, как указано в этот вопрос , вы можете использовать метод <a href="https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every" rel="nofollow noreferrer">every()</a>:

[1, 2, 3].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // true

[1, 2, 1].every(function(elem, i, array){return array.lastIndexOf(elem) === i}) // false

Обратите внимание, что every() не работает для IE 8 и ниже.

Я использую lastIndexOf(), потому что он может быть более эффективным, чем indexOf(), если функции обратного вызова, сделанные every(), выполняются в порядке индекса, но это не доказано.

В CoffeeScript Я использую это:

Array::duplicates = -> not @every((elem, i, array) -> array.lastIndexOf(elem) is i)

[1, 2, 3].duplicates() // false
[1, 2, 1].duplicates() // true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...