Получить все уникальные значения в массиве JavaScript (удалить дубликаты)

У меня есть массив чисел, которые я должен убедиться, что они уникальны. Я нашел фрагмент кода ниже в интернете, и он прекрасно работает, пока в массиве нет нуля. Я нашел этот другой скрипт здесь на SO, который выглядит почти так же, как и он, но он не дает сбоя.

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

Array.prototype.getUnique = function() {
 var o = {}, a = [], i, e;
 for (i = 0; e = this[i]; i++) {o[e] = 1};
 for (e in o) {a.push (e)};
 return a;
}

Больше ответов от дублирующего вопроса:

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

140 ответов

Если у вас все в порядке с дополнительными зависимостями или у вас уже есть одна из библиотек в вашей кодовой базе, вы можете удалить дубликаты из массива с помощью LoDash (или Underscore).

использование

Если у вас его нет в базе кода, установите его с помощью npm:

npm install lodash

Затем используйте его следующим образом:

import _ from 'lodash';
let idArray = _.uniq ([
    1,
    2,
    3,
    3,
    3
]);
console.dir(idArray);

Из:

[ 1, 2, 3 ]

В ES6/позже

Получить только уникальные значения

        let a = [
           { id: 1, name: "usman" },
           { id: 2, name: "zia" },
           { id: 3, name: "usman" },
          ];
const unique = [...new Set(a.map((item) => item.name))];
console.log(unique); // ["usman", "zia"]

Получите уникальные объекты

      const myObjArray = [
                       { id: 1, name: "usman" },
                       { id: 2, name: "zia" },
                       { id: 3, name: "usman" },
                   ];
// Creates an array of objects with unique "name" property values.
let uniqueObjArray = [
  ...new Map(myObjArray.map((item) => [item["name"], item])).values(),
];

console.log("uniqueObjArray", uniqueObjArray);

Из блога Шамасиса Бхаттачарьи (O(2n) сложность времени):

Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

Из блога Пола Айриша: улучшение JQuery .unique():

(function($){

    var _old = $.unique;

    $.unique = function(arr){

        // do the default behavior only if we got an array of elements
        if (!!arr[0].nodeType){
            return _old.apply(this,arguments);
        } else {
            // reduce the array to contain no dupes via grep/inArray
            return $.grep(arr,function(v,k){
                return $.inArray(v,arr) === k;
            });
        }
    };
})(jQuery);

// in use..
var arr = ['first',7,true,2,7,true,'last','last'];
$.unique(arr); // ["first", 7, true, 2, "last"]

var arr = [1,2,3,4,5,4,3,2,1];
$.unique(arr); // [1, 2, 3, 4, 5]

Я не уверен, почему Габриэль Сильвейра написал эту функцию, но более простая форма, которая работает для меня так же хорошо и без минимизации:

Array.prototype.unique = function() {
  return this.filter(function(value, index, array) {
    return array.indexOf(value, index + 1) < 0;
  });
};

или в CoffeeScript:

Array.prototype.unique = ->
  this.filter( (value, index, array) ->
    array.indexOf(value, index + 1) < 0
  )

Я обнаружил, что сериализация их хеш-ключа помогла мне заставить это работать для объектов.

Array.prototype.getUnique = function() {
        var hash = {}, result = [], key; 
        for ( var i = 0, l = this.length; i < l; ++i ) {
            key = JSON.stringify(this[i]);
            if ( !hash.hasOwnProperty(key) ) {
                hash[key] = true;
                result.push(this[i]);
            }
        }
        return result;
    }

Поиск уникальных значений Array простым методом

function arrUnique(a){
  var t = [];
  for(var x = 0; x < a.length; x++){
    if(t.indexOf(a[x]) == -1)t.push(a[x]);
  }
  return t;
}
arrUnique([1,4,2,7,1,5,9,2,4,7,2]) // [1, 4, 2, 7, 5, 9]

Странно, это не было предложено раньше.. чтобы удалить дубликаты по ключу объекта (id ниже) в массиве вы можете сделать что-то вроде этого:

const uniqArray = array.filter((obj, idx, arr) => (
  arr.findIndex((o) => o.id === obj.id) === idx
)) 

Для объектно-ориентированного массива с некоторыми уникальными идентификаторами у меня есть простое решение, с помощью которого вы можете сортировать по линейной сложности

function getUniqueArr(arr){
    const mapObj = {};
    arr.forEach(a => { 
       mapObj[a.id] = a
    })
    return Object.values(mapObj);
}

Создайте набор из массива и затем инициализируйте мелкую копию набора в желаемом контейнере.

let array = [1,2,3,2,1];
let uniqueArray = [... new Set(array)];

Задача - получить уникальный массив из массива, состоящего из произвольных типов (примитивных и не примитивных).

Подход, основанный на использовании new Map(...)не ново. Здесь это используетсяJSON.stringify(...), JSON.parse(...) а также [].mapметод. Преимущества - универсальность (применимость для массива любых типов), короткая нотация ES6 и, вероятно, производительность в этом случае:

const dedupExample = [
    { a: 1 },
    { a: 1 },
    [ 1, 2 ],
    [ 1, 2 ],
    1,
    1,
    '1',
    '1'
]

const getUniqArr = arr => {
    const arrStr = arr.map(item => JSON.stringify(item))
    return [...new Set(arrStr)]
        .map(item => JSON.parse(item))
}

console.info(getUniqArr(dedupExample))
   /* [ {a: 1}, [1, 2], 1, '1' ] */

Вы также можете использовать метод Array.from для преобразования Set в Array, если принятый ответ не будет работать на Typescript.

если вы получите сообщение об ошибке: Type 'Set<any>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.ts(2569)

      let uniques = Array.from(new Set([1, 2, 3, 1, 1])) ;
console.log(uniques);

С es6 (и поддерживает порядок):

[...new Set(myArray)];

Только одна строка кода:

          var arr = [1, 1, 2, 3] // example 
    var unique = new Set(arr) // 1, 2, 3
    console.log(unique) // 1, 2, 3 when I run in node.js

Чтобы решить эту проблему с другой стороны, может быть полезно не иметь дубликатов при загрузке массива, способ, которым объект Set мог бы это делать, но он пока недоступен во всех браузерах. Это экономит память и более эффективно, если вам нужно много раз просматривать его содержимое.

Array.prototype.add = function (elem) {
   if (this.indexOf(elem) == -1) {
      this.push(elem);
   }
}

Образец:

set = [];
[1,3,4,1,2,1,3,3,4,1].forEach(function(x) { set.add(x); });

Дает тебе set = [1,3,4,2]

Если кто-то использует http://knockoutjs.com/

ko.utils.arrayGetDistinctValues()

Кстати, посмотреть на все ko.utils.array* коммунальные услуги.

Уменьшите это!!!

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

['a', 1, 'a', 2, '1'].reduce((accumulator, currentValue) => accumulator.includes(currentValue) ? accumulator : [...accumulator, currentValue], [])

Пример теста:

var array = ['a', 1, 'a', 2, '1'];
const reducer = (accumulator, currentValue) => accumulator.includes(currentValue) ? accumulator : [...accumulator, currentValue];

console.log(
  array.reduce(reducer, [])
);

Вывод

Намного более элегантный и полезный, когда надоедает for-each подход хочет избежать (не то чтобы он бесполезен).

Нет необходимости во внешних библиотеках, таких как Underscore.js, JQuery или Lo-Dash, и нет проблем с созданием какой-либо встроенной функции для достижения желаемого эффекта дедупликации.

О, и ЭЙ!, это можно сделать однострочно!!!


Этот ответ был возможен благодаря ES5 (ECMAScript 2015) include() а также reduce().

Используя ключи объекта для создания уникального массива, я попробовал следующее

function uniqueArray( ar ) {
  var j = {};

  ar.forEach( function(v) {
    j[v+ '::' + typeof v] = v;
  });


  return Object.keys(j).map(function(v){
    return j[v];
  });
}   

uniqueArray(["1",1,2,3,4,1,"foo", false, false, null,1]);

Который возвращается ["1", 1, 2, 3, 4, "foo", false, null]

Вы также можете использовать JQuery

var a = [1,5,1,6,4,5,2,5,4,3,1,2,6,6,3,3,2,4];

// note: jQuery's filter params are opposite of javascript's native implementation :(
var unique = $.makeArray($(a).filter(function(i,itm){ 
    // note: 'index', not 'indexOf'
    return i == $(a).index(itm);
}));

// unique: [1, 5, 6, 4, 2, 3]

Первоначально ответил на: JQuery функцию, чтобы получить все уникальные элементы из массива?

Самый простой способ найти уникальный элемент с помощью метода фильтрации:

var A1 = [2,2,4,5,5,6,8,8,9];

var uniqueA1 = A1.filter(function(element){
    return A1.indexOf(element) == A1.lastIndexOf(element);
});

console.log(uniqueA1);

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

Output: 4,6,9

Поиск уникальных объектов в массиве с помощью One Liner

const uniqueBy = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
// f -> should must return string because it will be use as key

const data = [
  { comment: "abc", forItem: 1, inModule: 1 },
  { comment: "abc", forItem: 1, inModule: 1 },
  { comment: "xyz", forItem: 1, inModule: 2 },
  { comment: "xyz", forItem: 1, inModule: 2 },
];

uniqueBy(data, (x) => x.forItem +'-'+ x.inModule); // find unique by item with module
// output
// [
//   { comment: "abc", forItem: 1, inModule: 1 },
//   { comment: "xyz", forItem: 1, inModule: 2 },
// ];

// can also use for strings and number or other primitive values

uniqueBy([1, 2, 2, 1], (v) => v); // [1, 2]
uniqueBy(["a", "b", "a"], (v) => v); // ['a', 'b']

uniqueBy(
  [
    { id: 1, name: "abc" },
    { id: 2, name: "xyz" },
    { id: 1, name: "abc" },
  ],
  (v) => v.id
);
// output
// [
//   { id: 1, name: "abc" },
//   { id: 2, name: "xyz" },
// ];

Есть простой способ решить эту задачу через ES6 - используя Set:

let arr = [1, 1, 2, 2, 3, 3];
let deduped = [...new Set(arr)] // [1, 2, 3]

2021: Тест производительности для Node.js v12.14 и v14.15

Я взял основные алгоритмы с первой страницы ответов и проверил некоторые показатели производительности в Node.js v12, которая является моей целевой платформой. (Результаты были аналогичными в Node.js v14.15).

Мой код:

      var uniq1 = function(ar) {
  var item, j, len1, retar;
  retar = [];
  for (j = 0, len1 = ar.length; j < len1; j++) {
    item = ar[j];
    if (retar.indexOf(item) === -1 && item !== '') {
      retar.push(item);
    }
  }
  return retar;
};

var uniq2 = function(ar) {
  return [...new Set(ar)];
};

var uniq3 = function(ar, b, c) {
  b = ar.length;
  while (c = --b) {
    while (c--) {
      ar[b] !== ar[c] || ar.splice(c, 1);
    }
  }
  return ar;
};

var uniq4 = function(ar) {
  var onlyUnique;
  onlyUnique = function(value, index, self) {
    return self.indexOf(value) === index;
  };
  return ar.filter(onlyUnique);
};

var uniq5 = function(ar) {
  // lodash 4.5 uniq function
  return _.uniq(ar);
};

Приложение, которое вызовет эту функцию, будет иметь около 50 значений с примерно 15 уникальными посетителями. Я сгенерировал несколько случайных чисел, подходящих для этого случая:

      ar = [10,9,9,4,9,4,10,13,9,12,4,1,4,0,7,8,13,12,5,14,8,0,14,14,2,4,13,4,9,10,2,13,1,4,11,1,14,11,2,1,2,1,4,4,11,2,11,13,8,8]

Затем я запускал каждый тестовый пример 40000 раз на MacBook Pro c2015 г., и весь набор тестов был запущен несколько раз. Хотя затраченное время немного варьировалось между запусками, приведенные ниже числа являются типичными:

      ✔ uniq1: 39 ms
✔ uniq2: 51 ms
✔ uniq3: 19 ms
✔ uniq4: 67 ms
✔ (lodash) uniq5: 24 ms

Uniq3 - явный фаворит. В lodashрезультаты были очень похожи на, и я думаю, что прошедшее время немного медленнее связано с тем, что я заключил функцию lodash в свою функцию. Lodash, вероятно, использует тот же алгоритм, что и uniq3.

Дополнительные сведения о каждом из этих алгоритмов см. На первой странице ответов на этот вопрос.

Как уже объяснялось, [...new Set(values)] - лучший вариант, если он вам доступен.

В противном случае вот однострочник, который не выполняет итерацию массива для каждого индекса:

      values.sort().filter((val, index, arr) => index === 0 ? true : val !== arr[index - 1]);

Это просто сравнивает каждое значение с предыдущим. Результат будет отсортирован.

Как насчет использования набора?

   let productPrice = [230,560,125,230,678,45,230,125,127];

   let tempData = new Set(productPrice);
   let uniqeProductPrice = [...tempData];

   uniqeProductPrice.forEach((item)=>{
      console.log(item)
    });

Найден этот сладкий отрывок из поста по Changhui Xu для тех, кто хочет получить уникальные объекты. Однако я не сравнивал его производительность с другими альтернативами.

const array = [{
    name: 'Joe',
    age: 17
  },
  {
    name: 'Bob',
    age: 17
  },
  {
    name: 'Tom',
    age: 25
  },
  {
    name: 'John',
    age: 22
  },
  {
    name: 'Jane',
    age: 20
  },
];

const distinctAges = [...new Set(array.map(a => a.age))];

console.log(distinctAges)

Это будет работать

function getUnique(a) {
  var b = [a[0]], i, j, tmp;
  for (i = 1; i < a.length; i++) {
    tmp = 1;
    for (j = 0; j < b.length; j++) {
      if (a[i] == b[j]) {
        tmp = 0;
        break;
      }
    }
    if (tmp) {
      b.push(a[i]);
    }
  }
  return b;
}

Вот почти однострочник, который является O(n), сохраняет первый элемент и где вы можете сохранить поле, которое вы uniq'ing, отдельно.

Это довольно распространенный прием в функциональном программировании - вы используете reduceчтобы создать массив, который вы возвращаете. Поскольку мы строим массив таким образом, мы гарантируем, что получим стабильный порядок, в отличие от [...new Set(array)]подход. Мы по-прежнему используем a, чтобы убедиться, что у нас нет дубликатов, поэтому наш аккумулятор содержит как Set и массив, который мы строим.

Для пользователей TS!

      const uniq = <T>(arr: T[]) => [...new Set(arr)];

Посмотри на это. Jquery предоставляет метод uniq: https://api.jquery.com/jQuery.unique/

var ids_array = []

$.each($(my_elements), function(index, el) {
    var id = $(this).attr("id")
    ids_array.push(id)
});

var clean_ids_array = jQuery.unique(ids_array)

$.each(clean_ids_array, function(index, id) {
   elment = $("#" + id)   // my uniq element
   // TODO WITH MY ELEMENT
});

Вы можете использовать набор для устранения дубликатов.

      const originalNumbers = [1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 1, 2, 9];
const uniqueNumbersSet = new Set(originalNumbers);

/** get the array back from the set */
const uniqueNumbersArray = Array.from(uniqueNumbersSet);

/** uniqueNumbersArray outputs to: [1, 2, 3, 4, 5, 9] */

Узнайте больше о наборе: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set .

Другие вопросы по тегам