Получить все уникальные значения в массиве JavaScript (удалить дубликаты) - PullRequest
1123 голосов
/ 25 декабря 2009

У меня есть массив чисел, которые я должен убедиться, что они уникальны. Я нашел фрагмент кода ниже в интернете, и он прекрасно работает, пока в массиве нет нуля. Я нашел этот другой скрипт здесь, на 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;
}

Больше ответов на повторяющийся вопрос:

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

Ответы [ 70 ]

27 голосов
/ 15 января 2014

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

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

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

Array.from полезен для преобразования Set обратно в массив, чтобы у вас был легкий доступ ко всем удивительным методам (функциям), которые есть у массивов. Есть также другие способы сделать то же самое. Но вам может вообще не понадобиться 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) part становится вещью, которую мы назвали , результатом по завершении функции.

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

20 голосов
/ 19 сентября 2014
["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;
 }, []);
17 голосов
/ 27 июля 2012

Этот прототип getUnique не совсем корректен, потому что если у меня есть массив типа: ["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"].

16 голосов
/ 09 апреля 2018

Мы можем сделать это, используя наборы 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];
12 голосов
/ 17 апреля 2013

Не расширяя 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, Firefox OS, Sencha, Phonegap, Titanium, ...).

10 голосов
/ 28 ноября 2018

Магия

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) ))
10 голосов
/ 25 декабря 2009
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 голосов
/ 01 ноября 2011

Если вы используете Prototype Framework, вам не нужно делать циклы 'for', вы можете использовать http://www.prototypejs.org/api/array/uniq, например:

var a = Array.uniq();  

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

уник ()

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

размер ()

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

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

compact ()

раньше, вот так:

var a = Array.compact().uniq();  
10 голосов
/ 25 декабря 2009

Это потому, что 0 - ложное значение в JavaScript.

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

7 голосов
/ 11 октября 2018

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

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

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

console.log(objArr);
...