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

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

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

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;
}

Дополнительные ответы от дублирующего вопроса:

Аналогичный вопрос:

+1228
источник поделиться
80 ответов
  • 1
  • 2
  • 3

С JavaScript 1.6/ECMAScript 5 вы можете использовать собственный метод filter массива следующим образом, чтобы получить массив с уникальными значениями:

function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

filter собственных методов будет проходить через массив и оставить только те записи, которые передают данную функцию обратного вызова onlyUnique.

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

Это решение работает без дополнительной библиотеки, такой как jQuery или prototype.js.

Он также работает для массивов со смешанными типами значений.

Для старых браузеров (<ie9), которые не поддерживают filter собственных методов и indexOf вы можете найти работу в документации MDN для фильтра и indexOf.

Если вы хотите сохранить последнее вхождение значения, просто замените indexOf на lastIndexOf.

С ES6 это может быть сокращено:

// usage example:
var myArray = ['a', 1, 'a', 2, '1'];
var unique = myArray.filter((v, i, a) => a.indexOf(v) === i); 

// unique is ['a', 1, 2, '1']

Спасибо Камило Мартину за намек в комментарии.

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

var myArray = ['a', 1, 'a', 2, '1'];

let unique = [...new Set(myArray)]; 

// unique is ['a', 1, 2, '1']

Конструктор Set принимает итерируемый объект, такой как Array, и оператор спреда ... преобразует набор обратно в массив. Спасибо Lukas Liese за намек в комментарии.

+2250
источник

Обновленный ответ для ES6/ES2015. Используя Set, однострочное решение:

var items = [4,5,4,6,3,4,5,2,23,1,4,4,4]
var uniqueItems = Array.from(new Set(items))

Что возвращает

[4, 5, 6, 3, 2, 23, 1]

Как предложил le_m, это также можно сократить с помощью оператора распространения, например

var uniqueItems = [...new Set(items)]
+751
источник
другие ответы

Связанные вопросы


Похожие вопросы

Я понимаю, что этот вопрос уже содержит более 30 ответов. Но сначала я прочитал все существующие ответы и сделал собственные исследования.

Я разделил все ответы на 4 возможных решения:

  • Используйте новую функцию ES6: [...new Set( [1, 1, 2] )];
  • Использовать объект { } для предотвращения дублирования
  • Использовать вспомогательный массив [ ]
  • Используйте filter + indexOf

Здесь примеры кодов, найденные в ответах:

Использовать новую функцию ES6: [...new Set( [1, 1, 2] )];

function uniqueArray0(array) {
  var result = Array.from(new Set(array));
  return result    
}

Использовать объект { } для предотвращения дублирования

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

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

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

Использовать вспомогательный массив [ ]

function uniqueArray2(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

Использовать filter + indexOf

function uniqueArray3(a) {
  function onlyUnique(value, index, self) { 
      return self.indexOf(value) === index;
  }

  // usage
  var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']

  return unique;
}

И я подумал, какой из них быстрее. Я сделал образец Google Sheet для тестирования функций. Примечание. ECMA 6 недоступен в Google Таблицах, поэтому я не могу его протестировать.

Здесь результат тестов: введите описание изображения здесь

Я ожидал увидеть, что код с использованием объекта { } будет побежден, потому что он использует хеш. Поэтому я рад, что тесты показали наилучшие результаты для этого алгоритма в Chrome и IE. Благодаря @rab для кода.

+135
источник

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

console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>

который вернется:

[1, 2, 3, 4]
+130
источник

Один лайнер, чистый JavaScript

С синтаксисом ES6

list = list.filter((x, i, a) => a.indexOf(x) == i)

x --> item in array
i --> index of item
a --> array reference, (in this case "list")

введите описание изображения здесь

С синтаксисом ES5

list = list.filter(function (x, i, a) { 
    return a.indexOf(x) == i; 
});

Совместимость браузера: IE9 +

+60
источник

С тех пор я нашел хороший метод, который использует jQuery

arr = $.grep(arr, function(v, k){
    return $.inArray(v ,arr) === k;
});

Примечание: этот код был вытащен из Paul Irish duck punching post - Я забыл отдать должное: P

+52
источник

Самое короткое решение с ES6: [...new Set( [1, 1, 2] )];

Или, если вы хотите изменить прототип Array (как в исходном вопросе):

Array.prototype.getUnique = function() {
    return [...new Set( [this] )];
};

EcmaScript 6 частично реализована в современных браузерах в настоящий момент (август 2015 г.), но Babel стал очень популярным для пересылки ES6 (и даже ES7) обратно в ES5. Таким образом, вы можете написать код ES6 сегодня!

Если вам интересно, что означает ..., он называется оператором распространения . Из MDN: "Оператор спрединга позволяет расширять выражение в местах, где ожидаются несколько аргументов (для вызовов функций) или нескольких элементов (для литералов массива)". Поскольку Set является итерируемым (и может иметь только уникальные значения), оператор с расширением будет расширять набор, чтобы заполнить массив.

Ресурсы для обучения ES6:

+48
источник

Самое простое решение:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);

Или:

var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log(Array.from(new Set(arr)));
+35
источник

Самый простой и самый быстрый (в Chrome) способ сделать это:

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}

Просто просматривает каждый элемент массива, проверяет, находится ли этот элемент в списке, а если нет, нажмите на массив, который возвращается.

Согласно jsPerf, эта функция самая быстрая из тех, что я могу найти где угодно - не стесняйтесь добавлять свои собственные, хотя.

Версия, отличная от прототипа:

function uniques(arr) {
    var a = [];
    for (var i=0, l=arr.length; i<l; i++)
        if (a.indexOf(arr[i]) === -1 && arr[i] !== '')
            a.push(arr[i]);
    return a;
}

Сортировка

При необходимости также сортировать массив, самое быстрое:

Array.prototype.sortUnique = function() {
    this.sort();
    var last_i;
    for (var i=0;i<this.length;i++)
        if ((last_i = this.lastIndexOf(this[i])) !== i)
            this.splice(i+1, last_i-i);
    return this;
}

или не-прототип:

function sortUnique(arr) {
    arr.sort();
    var last_i;
    for (var i=0;i<arr.length;i++)
        if ((last_i = arr.lastIndexOf(arr[i])) !== i)
            arr.splice(i+1, last_i-i);
    return arr;
}

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

+31
источник

ТОЛЬКО ПРОИЗВОДИТЕЛЬНОСТЬ! этот код, вероятно, на 10 раз быстрее, чем все коды здесь * работает во всех браузерах, а также имеет самое низкое влияние на память.... и более

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

var array=[1,2,3,4,5,6,7,8,9,0,1,2,1];

то вы можете попробовать это

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 1];

function toUnique(a, b, c) { //array,placeholder,placeholder
  b = a.length;
  while (c = --b)
    while (c--) a[b] !== a[c] || a.splice(c, 1);
  return a // not needed ;)
}
console.log(toUnique(array));
//[3, 4, 5, 6, 7, 8, 9, 0, 2, 1]

Я придумал эту функцию, прочитав эту статью...

http://www.shamasis.net/2009/09/fast-algorithm-to-find-unique-items-in-javascript-array/

Мне не нравится цикл for. он имеет много параметров. я как цикл while. в то время как это самый быстрый цикл во всех браузерах, за исключением того, который нам всем нравится... chrome.

в любом случае я написал первую функцию, которая использует while.And yep это немного быстрее, чем функция, найденная в статье. Но этого недостаточно. unique2()

Следующий шаг использует современные js. Object.keys Я заменил другой цикл for на js1.7 Object.keys... немного быстрее и короче (в хромах 2x быстрее);). Недостаточно!. unique3().

В этот момент я думал о том, что мне действительно нужно в моей уникальной функции. Мне не нужен старый массив, я хочу быструю функцию. поэтому я использовал 2 в то время как петли + сращивание. unique4()

Бесполезно говорить, что я был впечатлен.

chrome: обычные 150 000 операций в секунду подскочили до 1 800 000 операций в секунду.

то есть: 80 000 оп/с против 3500 000 оп/с

ios: 18 000 оп/с против 170 000 оп/с

сафари: 80 000 оп/с против 6 000 000 оп/с

Proof http://jsperf.com/wgu или лучше использовать console.time... microtime... whatever

unique5() - это просто показать вам, что произойдет, если вы хотите сохранить старый массив.

Не используйте Array.prototype, если вы не знаете, что делаете. Я просто много копировал и прошёл. Используйте Object.defineProperty(Array.prototype,...,writable:false,enumerable:false}), если вы хотите создать собственный prototype.example: fooobar.com/questions/13026/...

Demo http://jsfiddle.net/46S7g/

ПРИМЕЧАНИЕ: ваш старый массив уничтожается/становится после этой операции.

если вы не можете прочитать приведенный выше код, прочитайте javascript книгу или вот некоторые объяснения относительно более короткого кода. fooobar.com/questions/1682/...

некоторые используют indexOf... не... http://jsperf.com/dgfgghfghfghghgfhgfhfghfhgfh

для пустых массивов

!array.length||toUnique(array); 
+30
источник

Многие из ответов здесь могут быть бесполезны для начинающих. Если дедупликация массива затруднена, они действительно будут знать о цепочке прототипов или даже jQuery?

В современных браузерах чистое и простое решение - хранить данные в наборе, который представляет собой список уникальных значений.

const cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
const uniqueCars = Array.from(new Set(cars));

Array.from полезен для преобразования Set обратно в Array, чтобы у вас был легкий доступ ко всем удивительным методам (функциям), которые есть у массивов. Есть и другие способы сделать то же самое. Но вам может не понадобиться Array.from, так как наборы имеют множество полезных функций, таких как forEach.

Если вам требуется поддержка старого Internet Explorer и, следовательно, вы не можете использовать Set, тогда простой способ - скопировать элементы в новый массив, предварительно проверив, находятся ли они уже в новом массиве.

// Create a list of cars, with duplicates.
var cars = ['Volvo', 'Jeep', 'Volvo', 'Lincoln', 'Lincoln', 'Ford'];
// Create a list of unique cars, to put a car in if we haven't already.
var uniqueCars = [];

// Go through each car, one at a time.
cars.forEach(function (car) {
    // The code within the following block runs only if the
    // current car does NOT exist in the uniqueCars list
    // - a.k.a. prevent duplicates
    if (uniqueCars.indexOf(car) === -1) {
        // Since we now know we haven't seen this car before,
        // copy it to the end of the uniqueCars list.
        uniqueCars.push(car);
    }
});

Чтобы сделать это мгновенно повторно используемым, давайте включим его в функцию.

function deduplicate(data) {
    if (data.length > 0) {
        var result = [];

        data.forEach(function (elem) {
            if (result.indexOf(elem) === -1) {
                result.push(elem);
            }
        });

        return result;
    }
}

Таким образом, чтобы избавиться от дубликатов, мы бы сейчас сделали это.

var uniqueCars = deduplicate(cars);

deduplicate(cars) становится тем, что мы назвали результатом, когда функция завершается.

Просто передайте ему имя любого массива, который вам нравится.

+27
источник
["Defects", "Total", "Days", "City", "Defects"].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);

[0,1,2,0,3,2,1,5].reduce(function(prev, cur) {
  return (prev.indexOf(cur) < 0) ? prev.concat([cur]) : prev;
 }, []);
+20
источник

Этот прототип getUnique не совсем корректен, потому что если у меня есть Array like: ["1",1,2,3,4,1,"foo"], он вернет ["1","2","3","4"], а "1" будет строкой, а 1 будет целочисленным; они разные.

Вот правильное решение:

Array.prototype.unique = function(a){
    return function(){ return this.filter(a) }
}(function(a,b,c){ return c.indexOf(a,b+1) < 0 });

с помощью:

var foo;
foo = ["1",1,2,3,4,1,"foo"];
foo.unique();

Вышеуказанное будет выдавать ["1",2,3,4,1,"foo"].

+17
источник

Мы можем сделать это, используя наборы ES6:

var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));

console.log(uniqueArray);

//Вывод будет

uniqueArray = [1,2,3,4,5];
+17
источник

Без расширения Array.prototype(как говорят, это плохая практика) или с помощью jquery/underscore вы можете просто filter массива.

Сохраняя последнее вхождение:

    function arrayLastUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps last occurrence
            return c.indexOf(a, b + 1) < 0;
        });
    },

или первое вхождение:

    function arrayFirstUnique(array) {
        return array.filter(function (a, b, c) {
            // keeps first occurrence
            return c.indexOf(a) === b;
        });
    },

Ну, это только javascript ECMAScript 5+, что означает только IE9 +, но это хорошо для разработки в родном HTML/JS (приложение для Windows Store, Firefox OS, Sencha, Phonegap, Titanium,...).

+12
источник

магия

a.filter(e=>!(t[e]=e in t)) 

O (N) производительность; мы предполагаем, что ваш массив находится в a и t={}. Объяснение здесь (+ Jeppe impr.)

let t={}, unique= a=> a.filter(e=>!(t[e]=e in t));

// "stand-alone" version working with global t:
// a1.filter((t={},e=>!(t[e]=e in t)));

// Test data
let a1 = [5,6,0,4,9,2,3,5,0,3,4,1,5,4,9];
let a2 = [[2, 17], [2, 17], [2, 17], [1, 12], [5, 9], [1, 12], [6, 2], [1, 12]];
let a3 = ['Mike', 'Adam','Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];

// Results
console.log(JSON.stringify( unique(a1) ))
console.log(JSON.stringify( unique(a2) ))
console.log(JSON.stringify( unique(a3) ))
+12
источник

Если вы используете Prototype framework, вам не нужно делать "для" циклов, вы можете использовать http://www.prototypejs.org/api/array/uniq следующим образом:

var a = Array.uniq();  

Будет создан дублированный массив без дубликатов. Я наткнулся на ваш вопрос, ища метод для подсчета различных записей массивов, поэтому после

Uniq()

Я использовал

размер()

и был мой простой результат. постскриптум Извините, если я что-то испортил.

edit: если вы хотите избежать записи undefined, вы можете добавить

compact()

раньше, например:

var a = Array.compact().uniq();  
+11
источник

Это потому, что 0 является фальшивым значением в JavaScript.

this[i] будет ложным, если значение массива равно 0 или любое другое значение фальши.

+10
источник
Array.prototype.getUnique = function() {
    var o = {}, a = []
    for (var i = 0; i < this.length; i++) o[this[i]] = 1
    for (var e in o) a.push(e)
    return a
}
+10
источник
[...new Set(duplicates)]

Это самый простой способ, на который ссылаются Документы MDN Web.

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)]) // [2, 3, 4, 5, 6, 7, 32]
+10
источник

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

let objArr = [{
  id: '123'
}, {
  id: '123'
}, {
  id: '456'
}];

objArr = objArr.reduce((acc, cur) => [
  ...acc.filter((obj) => obj.id !== cur.id), cur
], []);

console.log(objArr);
+7
источник

Из блог Шамаси Бхаттачарья (сложность времени 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]
+6
источник

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

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
  )
+6
источник

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

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]
+6
источник

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

const uniqArray = array.filter((obj, idx, arr) => (
  arr.findIndex((o) => o.id === obj.id) === idx
)) 
+6
источник

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

[...new Set(myArray)];
+6
источник

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

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

console.log([...new Set(names)])
+6
источник

Похоже, мы потеряли ответ рафаэля, который считался принятым ответом в течение нескольких лет. Это было (по крайней мере, в 2017 году) самое эффективное решение , если у вас нет массива смешанного типа:

Array.prototype.getUnique = function(){
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
return a;
}

Если у вас есть массив смешанного типа, вы можете сериализовать ключ хеша:

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;
}
+5
источник

Чтобы решить проблему, наоборот, может быть полезно иметь дубликат при загрузке массива, способ 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]

+5
источник

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

let array = [1,2,3,2,1];
let uniqueArray = [... new Set(array)];
+5
источник
  • 1
  • 2
  • 3

Посмотрите другие вопросы по меткам или Задайте вопрос