Удалить повторяющиеся значения из массива JS

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

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

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

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

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

54 ответа

Решение

Быстро и грязно, используя jQuery:

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
    if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});

"Умный", но наивный способ

uniqueArray = a.filter(function(item, pos) {
    return a.indexOf(item) == pos;
})

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

Используя 3-й ("этот массив") параметр обратного вызова фильтра, мы можем избежать закрытия переменной массива:

uniqueArray = a.filter(function(item, pos, self) {
    return self.indexOf(item) == pos;
})

Хотя этот алгоритм и лаконичен, он не особенно эффективен для больших массивов (квадратичное время).

Hashtables на помощь

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

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

  • поскольку хеш-ключи могут быть только строками в Javascript, этот код не различает числа и "числовые строки". То есть, uniq([1,"1"]) вернется только [1]
  • по той же причине все объекты будут считаться равными: uniq([{foo:1},{foo:2}]) вернется только [{foo:1}],

Тем не менее, если ваши массивы содержат только примитивы и вам не нужны типы (например, это всегда числа), это решение является оптимальным.

Лучшее из двух миров

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

function uniq(a) {
    var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];

    return a.filter(function(item) {
        var type = typeof item;
        if(type in prims)
            return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
        else
            return objs.indexOf(item) >= 0 ? false : objs.push(item);
    });
}

сортировать | уник

Другой вариант - сначала отсортировать массив, а затем удалить каждый элемент, равный предыдущему:

function uniq(a) {
    return a.sort().filter(function(item, pos, ary) {
        return !pos || item != ary[pos - 1];
    })
}

Опять же, это не работает с объектами (потому что все объекты равны для sort). Кроме того, мы молча меняем исходный массив как побочный эффект - не хорошо! Однако, если ваш вход уже отсортирован, это путь (просто удалите sort из вышесказанного).

Уникальный по...

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

function uniqBy(a, key) {
    var seen = {};
    return a.filter(function(item) {
        var k = key(item);
        return seen.hasOwnProperty(k) ? false : (seen[k] = true);
    })
}

Особенно полезно key() является JSON.stringify который удалит объекты, которые физически отличаются, но "выглядят" одинаково:

a = [[1,2,3], [4,5,6], [1,2,3]]
b = uniqBy(a, JSON.stringify)
console.log(b) // [[1,2,3], [4,5,6]]

Если key не примитивно, вам придется прибегнуть к линейному поиску:

function uniqBy(a, key) {
    var index = [];
    return a.filter(function (item) {
        var k = key(item);
        return index.indexOf(k) >= 0 ? false : index.push(k);
    });
}

В ES6 вы можете использовать Set:

function uniqBy(a, key) {
    var seen = new Set();
    return a.filter(item => {
        var k = key(item);
        return seen.has(k) ? false : seen.add(k);
    });
}

или Map:

function uniqBy(a, key) {
    return [
        ...new Map(
            myArr.map(x => [key(x), x])
        ).values()
    ]
}

которые также работают с не примитивными ключами.

Библиотеки

Оба подчеркивания и Lo-Dash обеспечивают uniq методы. Их алгоритмы в основном аналогичны первому фрагменту выше и сводятся к следующему:

var result = [];
a.forEach(function(item) {
     if(result.indexOf(item) < 0) {
         result.push(item);
     }
});

Это квадратично, но есть и хорошие плюсы, такие как перенос indexOf, возможность uniqify по ключу (iteratee на их языке) и оптимизации для уже отсортированных массивов.

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

  $.uniqArray = function(a) {
        return $.grep(a, function(item, pos) {
            return $.inArray(item, a) === pos;
        });
  }

что, опять же, вариант первого фрагмента.

Спектакль

Вызовы функций в Javascript дороги, поэтому приведенные выше решения, какими бы краткими они ни были, не особенно эффективны. Для максимальной производительности замените filter с помощью цикла и избавиться от других вызовов функций:

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

Этот кусок уродливого кода делает то же самое, что и фрагмент № 3 выше, но на порядок быстрее (по сравнению с 2017 годом он только в два раза быстрее - основные сотрудники JS делают отличную работу!)

function uniq(a) {
    var seen = {};
    return a.filter(function(item) {
        return seen.hasOwnProperty(item) ? false : (seen[item] = true);
    });
}

function uniq_fast(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

/////

var r = [0,1,2,3,4,5,6,7,8,9],
    a = [],
    LEN = 1000,
    LOOPS = 1000;

while(LEN--)
    a = a.concat(r);

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq(a);
document.write('<br>uniq, ms/loop: ' + (new Date() - d)/LOOPS)

var d = new Date();
for(var i = 0; i < LOOPS; i++)
    uniq_fast(a);
document.write('<br>uniq_fast, ms/loop: ' + (new Date() - d)/LOOPS)

ES6

ES6 предоставляет объект Set, который делает вещи намного проще:

function uniq(a) {
   return Array.from(new Set(a));
}

или же

let uniq = a => [...new Set(a)];

Обратите внимание, что, в отличие от Python, наборы ES6 повторяются в порядке вставки, поэтому этот код сохраняет порядок исходного массива.

Однако, если вам нужен массив с уникальными элементами, почему бы не использовать множества с самого начала?

Генераторы

"Ленивая", основанная на генераторе версия uniq может быть построен на той же основе:

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

function* uniqIter(a) {
    let seen = new Set();

    for (let x of a) {
        if (!seen.has(x)) {
            seen.add(x);
            yield x;
        }
    }
}

// example:

function* randomsBelow(limit) {
    while (1)
        yield Math.floor(Math.random() * limit);
}

// note that randomsBelow is endless

count = 20;
limit = 30;

for (let r of uniqIter(randomsBelow(limit))) {
    console.log(r);
    if (--count === 0)
        break
}

// exercise for the reader: what happens if we set `limit` less than `count` and why

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

Uniq уменьшить при сохранении существующего порядка

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

var uniq = names.reduce(function(a,b){
    if (a.indexOf(b) < 0 ) a.push(b);
    return a;
  },[]);

console.log(uniq, names) // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

// one liner
return names.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);

Быстрее Уник с сортировкой

Возможно, есть более быстрые способы, но этот довольно приличный.

var uniq = names.slice() // slice makes copy of array before sorting it
  .sort(function(a,b){
    return a > b;
  })
  .reduce(function(a,b){
    if (a.slice(-1)[0] !== b) a.push(b); // slice(-1)[0] means last item in array without removing it (like .pop())
    return a;
  },[]); // this empty array becomes the starting value for a

// one liner
return names.slice().sort(function(a,b){return a > b}).reduce(function(a,b){if (a.slice(-1)[0] !== b) a.push(b);return a;},[]);

Обновление 2015: версия ES6:

В ES6 у вас есть Sets and Spread, что позволяет очень легко и эффективно удалить все дубликаты:

var uniq = [ ...new Set(names) ]; // [ 'Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Carl' ]

Сортировать по происхождению:

Кто-то спросил об упорядочении результатов на основе количества уникальных имен:

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 sorted = Object.keys(uniq).sort((a, b) => uniq[a] < uniq[b])

console.log(sorted)

Vanilla JS: удаление дубликатов с использованием объекта, подобного набору

Вы всегда можете попробовать поместить его в объект, а затем перебирать его ключи:

function remove_duplicates(arr) {
    var obj = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        obj[arr[i]] = true;
    }
    for (var key in obj) {
        ret_arr.push(key);
    }
    return ret_arr;
}

Vanilla JS: удаление дубликатов путем отслеживания уже увиденных значений (в порядке заказа)

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

function remove_duplicates_safe(arr) {
    var seen = {};
    var ret_arr = [];
    for (var i = 0; i < arr.length; i++) {
        if (!(arr[i] in seen)) {
            ret_arr.push(arr[i]);
            seen[arr[i]] = true;
        }
    }
    return ret_arr;

}

ECMAScript 6: Использовать новую структуру данных Set (в порядке заказа)

ECMAScript 6 добавляет новый Set Структура данных, которая позволяет хранить значения любого типа. Set.values возвращает элементы в порядке вставки.

function remove_duplicates_es6(arr) {
    let s = new Set(arr);
    let it = s.values();
    return Array.from(it);
}

Пример использования:

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

b = remove_duplicates(a);
// b:
// ["Adam", "Carl", "Jenny", "Matt", "Mike", "Nancy"]

c = remove_duplicates_safe(a);
// c:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

d = remove_duplicates_es6(a);
// d:
// ["Mike", "Matt", "Nancy", "Adam", "Jenny", "Carl"]

Однострочная версия с использованием фильтра массива и функций indexOf:

arr = arr.filter (function (value, index, array) { 
    return array.indexOf (value) == index;
});

Используйте http://underscorejs.org/

Это библиотека с множеством функций для манипулирования массивами.

Это - связь, чтобы согласиться с смокингом jQuery и подтяжками Backbone.js.

_.uniq

_.uniq(array, [isSorted], [iterator]) Псевдоним: уникальный
Создает версию массива без дубликатов, используя === для проверки равенства объектов. Если вы заранее знаете, что массив отсортирован, передача true для isSorted выполнит намного более быстрый алгоритм. Если вы хотите вычислить уникальные элементы на основе преобразования, передайте функцию итератора.

пример

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

alert(_.uniq(names, false));

Примечание: Lo-Dash (конкурент с подчеркиванием) также предлагает сопоставимую реализацию .uniq.

Одна линия:

let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);

Вы можете просто сделать это в JavaScript, с помощью второго - index - параметра filter метод:

var a = [2,3,4,5,5,4];
a.filter(function(value, index){ return a.indexOf(value) == index });

или короткой рукой

a.filter((v,i) => a.indexOf(v) == i)

использование Array.filter() как это

var actualArr = ['Apple', 'Apple', 'Banana', 'Mango', 'Strawberry', 'Banana'];

console.log('Actual Array: ' + actualArr);

var filteredArr = actualArr.filter(function(item, index) {
  if (actualArr.indexOf(item) == index)
    return item;
});

console.log('Filtered Array: ' + filteredArr);

в ES6 это можно сделать короче

actualArr.filter((item,index,self) => self.indexOf(item)==index);

Вот хорошее объяснение Array.filter()

Лучшие ответы имеют сложность O(n²), но это можно сделать просто O(n) используя объект в качестве хеша:

function getDistinctArray(arr) {
    var dups = {};
    return arr.filter(function(el) {
        var hash = el.valueOf();
        var isDup = dups[hash];
        dups[hash] = true;
        return !isDup;
    });
}

Это будет работать для строк, чисел и дат. Если ваш массив содержит сложные объекты (т. Е. Их необходимо сравнивать с ===), вышеуказанное решение не будет работать. Вы можете получить O(n) реализация для объектов путем установки флага на сам объект:

function getDistinctObjArray(arr) {
    var distinctArr = arr.filter(function(el) {
        var isDup = el.inArray;
        el.inArray = true;
        return !isDup;
    });
    distinctArr.forEach(function(el) {
        delete el.inArray;
    });
    return distinctArr;
}

Самый краткий способ удалить дубликаты из массива с использованием встроенных функций JavaScript - использовать последовательность, как показано ниже:

vals.sort().reduce(function(a, b){ if (b != a[0]) a.unshift(b); return a }, [])

нет необходимости slice ни indexOf в рамках функции сокращения, как я видел в других примерах! имеет смысл использовать его вместе с функцией фильтра:

vals.filter(function(v, i, a){ return i == a.indexOf(v) })

Еще один ES6(2015) способ сделать это, который уже работает в нескольких браузерах:

Array.from(new Set(vals))

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

[...new Set(vals)]

ура!

Самый простой, с которым я столкнулся до сих пор. В эс6.

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

 var noDupe = Array.from(new Set(names))

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

Решение 1

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

Решение 2 (используя Set)

Array.prototype.unique = function() {
    return Array.from(new Set(this));
}

Тестовое задание

var x=[1,2,3,3,2,1];
x.unique() //[1,2,3]

Спектакль

Когда я протестировал обе реализации (с Set и без Set) на производительность в Chrome, я обнаружил, что та, что с Set, намного быстрее!

Array.prototype.unique1 = function() {
    var a = [];
    for (i = 0; i < this.length; i++) {
        var current = this[i];
        if (a.indexOf(current) < 0) a.push(current);
    }
    return a;
}


Array.prototype.unique2 = function() {
    return Array.from(new Set(this));
}

var x=[];
for(var i=0;i<10000;i++){
 x.push("x"+i);x.push("x"+(i+1));
}

console.time("unique1");
console.log(x.unique1());
console.timeEnd("unique1");



console.time("unique2");
console.log(x.unique2());
console.timeEnd("unique2");

В ECMAScript 6 (он же ECMAScript 2015) Set может быть использован для фильтрации дубликатов. Затем он может быть преобразован обратно в массив с помощью оператора распространения.

var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"],
    unique = [...new Set(names)];

Перейти на это:

var uniqueArray = duplicateArray.filter(function(elem, pos) {
    return duplicateArray.indexOf(elem) == pos;
}); 

Теперь uniqueArray не содержит дубликатов.

Следующее более чем на 80% быстрее, чем перечисленный метод jQuery (см. Тесты ниже). Это ответ на аналогичный вопрос несколько лет назад. Если я сталкиваюсь с человеком, который первоначально предложил это, я отправлю кредит. Чистый JS.

var temp = {};
for (var i = 0; i < array.length; i++)
  temp[array[i]] = true;
var r = [];
for (var k in temp)
  r.push(k);
return r;

Мое сравнение тестовых случаев: http://jsperf.com/remove-duplicate-array-tests

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

Я считаю, что это лучший способ сделать это

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = Object.keys(myArray.reduce((p,c) => (p[c] = true,p),{}));
console.log(reduced);

Хорошо... хотя это O(n), а остальные O(n^2), мне было любопытно увидеть сравнение эталонных тестов между этой таблицей уменьшения / поиска и комбинацией filter/indexOf (я выбрал очень хорошую реализацию Jeetendras /questions/10960523/oshibka-pri-udalenii-dublikatov-iz-massiva-javascript/10960533#10960533). Я готовлю массив из 100КБ, заполненный случайными положительными целыми числами в диапазоне 0-9999, и он удаляет дубликаты. Я повторяю тест 10 раз, и средние результаты показывают, что они не совпадают по производительности.

  • В Firefox v47 уменьшить & lut: 14,85 мс против фильтра и indexOf: 2836 мс
  • В Chrome v51 уменьшение & lut: 23,90 мс против фильтра и indexOf: 1066 мс

Ну хорошо, пока все хорошо. Но давайте сделаем это правильно в этот раз в стиле ES6. Это выглядит так круто..! Но на данный момент, как он будет работать против мощного решения Lut, для меня загадка. Давайте сначала посмотрим код, а затем сравните его.

var myArray = [100, 200, 100, 200, 100, 100, 200, 200, 200, 200],
    reduced = [...myArray.reduce((p,c) => p.set(c,true),new Map()).keys()];
console.log(reduced);

Вау, это было коротко..! Но как насчет производительности..? Это прекрасно... Так как большой вес фильтра / indexOf перевалил за наши плечи, теперь я могу протестировать массив 1M случайных элементов натуральных чисел в диапазоне 0..99999, чтобы получить среднее значение из 10 последовательных тестов. Я могу сказать, что на этот раз это настоящий матч. Смотрите результат для себя:)

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 10;
for (var i = 0; i<count; i++){
  ranar = (new Array(1000000).fill(true)).map(e => Math.floor(Math.random()*100000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

Какой бы вы использовали..? Ну, не так быстро...! Не обманывайтесь. Карта находится в смещении. Теперь посмотрите... во всех вышеупомянутых случаях мы заполняем массив размером n числами диапазона

var ranar = [],
     red1 = a => Object.keys(a.reduce((p,c) => (p[c] = true,p),{})),
     red2 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*100000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("reduce & lut took: " + avg1 + "msec");
console.log("map & spread took: " + avg2 + "msec");

Теперь это захватывающее возвращение Map()..! Может быть, теперь вы можете принять лучшее решение, когда вы хотите удалить обманщиков.

Ну ладно, теперь мы все счастливы. Но главная роль всегда идет с аплодисментами. Я уверен, что некоторые из вас задаются вопросом, что будет делать объект Set. Теперь, когда мы открыты для ES6 и знаем, что Map - победитель предыдущих игр, давайте сравним Map с Set как финал. На этот раз типичная игра "Реал Мадрид - Барселона"... или это так? Посмотрим, кто победит в эль классико:)

var ranar = [],
     red1 = a => reduced = [...a.reduce((p,c) => p.set(c,true),new Map()).keys()],
     red2 = a => Array.from(new Set(a)),
     avg1 = [],
     avg2 = [],
       ts = 0,
       te = 0,
     res1 = [],
     res2 = [],
     count= 100;
for (var i = 0; i<count; i++){
  ranar = (new Array(100000).fill(true)).map(e => Math.floor(Math.random()*10000000));
  ts = performance.now();
  res1 = red1(ranar);
  te = performance.now();
  avg1.push(te-ts);
  ts = performance.now();
  res2 = red2(ranar);
  te = performance.now();
  avg2.push(te-ts);
}

avg1 = avg1.reduce((p,c) => p+c)/count;
avg2 = avg2.reduce((p,c) => p+c)/count;

console.log("map & spread took: " + avg1 + "msec");
console.log("set & A.from took: " + avg2 + "msec");

Вау.. человек..! Что ж, неожиданно это вовсе не оказалось el classico. Больше похоже на ФК Барселона против CA Osasuna:))

Вот простой ответ на вопрос.

var names = ["Alex","Tony","James","Suzane", "Marie", "Laurence", "Alex", "Suzane", "Marie", "Marie", "James", "Tony", "Alex"];
var uniqueNames = [];

    for(var i in names){
        if(uniqueNames.indexOf(names[i]) === -1){
            uniqueNames.push(names[i]);
        }
    }

Простой, но эффективный метод, это использовать filter метод в сочетании с фильтром function(value, index){ return this.indexOf(value) == index },

Пример кода:

var data = [2,3,4,5,5,4];
var filter = function(value, index){ return this.indexOf(value) == index };
var filteredData = data.filter(filter, data );

document.body.innerHTML = '<pre>' + JSON.stringify(filteredData, null, '\t') +  '</pre>';

Смотрите также эту скрипку.

Здесь очень простой для понимания и работы в любом месте (даже в PhotoshopScript) код. Проверь это!

var peoplenames = new Array("Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl");

peoplenames = unique(peoplenames);
alert(peoplenames);

function unique(array){
    var len = array.length;
    for(var i = 0; i < len; i++) for(var j = i + 1; j < len; j++) 
        if(array[j] == array[i]){
            array.splice(j,1);
            j--;
            len--;
        }
    return array;
}

//*result* peoplenames == ["Mike","Matt","Nancy","Adam","Jenny","Carl"]

Итак, варианты есть:

let a = [11,22,11,22];
let b = []


b = [ ...new Set(a) ];     
// b = [11, 22]

b = Array.from( new Set(a))   
// b = [11, 22]

b = a.filter((val,i)=>{
  return a.indexOf(val)==i
})                        
// b = [11, 22]

вот простой метод без каких-либо специальных библиотек, специальные функции,

name_list = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
get_uniq = name_list.filter(function(val,ind) { return name_list.indexOf(val) == ind; })

console.log("Original name list:"+name_list.length, name_list)
console.log("\n Unique name list:"+get_uniq.length, get_uniq)

Помимо того, что я был более простым и более кратким решением, чем текущие ответы (за исключением перспективных ES6), я проверил это, и оно оказалось намного быстрее:

var uniqueArray = dupeArray.filter(function(item, i, self){
  return self.lastIndexOf(item) == i;
});

Одно предостережение: Array.lastIndexOf() был добавлен в IE9, поэтому, если вам нужно пойти ниже, вам нужно искать в другом месте.

for (i=0; i<originalArray.length; i++) {  
    if (!newArray.includes(originalArray[i])) {
        newArray.push(originalArray[i]); 
    }
}

Общий функциональный подход

Вот общий и строго функциональный подход с ES2015:

// small, reusable auxiliary functions

const apply = f => a => f(a);

const flip = f => b => a => f(a) (b);

const uncurry = f => (a, b) => f(a) (b);

const push = x => xs => (xs.push(x), xs);

const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const some = f => xs => xs.some(apply(f));


// the actual de-duplicate function

const uniqueBy = f => foldl(
   acc => x => some(f(x)) (acc)
    ? acc
    : push(x) (acc)
 ) ([]);


// comparators

const eq = y => x => x === y;

// string equality case insensitive :D
const seqCI = y => x => x.toLowerCase() === y.toLowerCase();


// mock data

const xs = [1,2,3,1,2,3,4];

const ys = ["a", "b", "c", "A", "B", "C", "D"];


console.log( uniqueBy(eq) (xs) );

console.log( uniqueBy(seqCI) (ys) );

Мы можем легко вывести unique от unqiueBy или используйте более быструю реализацию, используя Set s:

const unqiue = uniqueBy(eq);

// const unique = xs => Array.from(new Set(xs));

Преимущества этого подхода:

  • общее решение с использованием отдельной функции компаратора
  • декларативная и краткая реализация
  • повторное использование других небольших общих функций

Вопросы производительности

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

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

Потребление памяти и сборка мусора

uniqueBy использует мутации (push(x) (acc) спрятано внутри его тела. Он использует аккумулятор вместо того, чтобы выбрасывать его после каждой итерации. Это уменьшает потребление памяти и давление ГХ. Поскольку этот побочный эффект находится внутри функции, все снаружи остается чистым.

Если случайно вы использовали

D3.js

Вы могли бы сделать

d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]

https://github.com/mbostock/d3/wiki/Arrays

Небольшая модификация превосходного ответа thg435 на использование собственного компаратора:

function contains(array, obj) {
    for (var i = 0; i < array.length; i++) {
        if (isEqual(array[i], obj)) return true;
    }
    return false;
}
//comparator
function isEqual(obj1, obj2) {
    if (obj1.name == obj2.name) return true;
    return false;
}
function removeDuplicates(ary) {
    var arr = [];
    return ary.filter(function(x) {
        return !contains(arr, x) && arr.push(x);
    });
}

Следующий скрипт возвращает новый массив, содержащий только уникальные значения. Работает со строками и числами. Нет необходимости в дополнительных библиотеках, только ванильный JS.

Поддержка браузера:

Feature Chrome  Firefox (Gecko)     Internet Explorer   Opera   Safari
Basic support   (Yes)   1.5 (1.8)   9                   (Yes)   (Yes)

https://jsfiddle.net/fzmcgcxv/3/

var duplicates = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl","Mike","Mike","Nancy","Carl"]; 
var unique = duplicates.filter(function(elem, pos) {
    return duplicates.indexOf(elem) == pos;
  }); 
alert(unique);
$(document).ready(function() {

    var arr1=["dog","dog","fish","cat","cat","fish","apple","orange"]

    var arr2=["cat","fish","mango","apple"]

    var uniquevalue=[];
    var seconduniquevalue=[];
    var finalarray=[];

    $.each(arr1,function(key,value){

       if($.inArray (value,uniquevalue) === -1)
       {
           uniquevalue.push(value)

       }

    });

     $.each(arr2,function(key,value){

       if($.inArray (value,seconduniquevalue) === -1)
       {
           seconduniquevalue.push(value)

       }

    });

    $.each(uniquevalue,function(ikey,ivalue){

        $.each(seconduniquevalue,function(ukey,uvalue){

            if( ivalue == uvalue)

            {
                finalarray.push(ivalue);
            }   

        });

    });
    alert(finalarray);
});

Хотя решение ES6 является лучшим, я озадачен тем, как никто не показал следующее решение:

function removeDuplicates(arr){
    o={}
    arr.forEach(function(e){
        o[e]=true
    })
    return Object.keys(o)
}

Здесь следует помнить, что объекты ДОЛЖНЫ иметь уникальные ключи. Мы используем это, чтобы удалить все дубликаты. Я бы подумал, что это будет самое быстрое решение (до ES6).

Имейте в виду, что это также сортирует массив.

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