Ответ 1
Быстрое и грязное использование 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);
});
У меня очень простой массив JavaScript, который может содержать или не содержать дубликаты.
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
Мне нужно удалить дубликаты и поместить уникальные значения в новый массив.
Я мог бы указать на все коды, которые я пробовал, но считаю это бесполезным, потому что они не работают. Я также принимаю решения jQuery.
Быстрое и грязное использование 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);
});
Использование Set конструктора и распространяемого синтаксиса:
uniq = [...new Set(array)];
uniqueArray = a.filter(function(item, pos) {
return a.indexOf(item) == pos;
})
По сути, мы перебираем массив и для каждого элемента проверяем, равна ли первая позиция этого элемента в массиве текущей позиции. Очевидно, что эти две позиции различны для дублирующих элементов.
Используя третий ("этот массив") параметр обратного вызова фильтра, мы можем избежать закрытия переменной массива:
uniqueArray = a.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
})
Несмотря на краткость, этот алгоритм не особенно эффективен для больших массивов (квадратичное время).
function uniq(a) {
var seen = {};
return a.filter(function(item) {
return seen.hasOwnProperty(item) ? false : (seen[item] = true);
});
}
Вот как это обычно делается. Идея состоит в том, чтобы поместить каждый элемент в хеш-таблицу, а затем немедленно проверить его наличие. Это дает нам линейное время, но имеет как минимум два недостатка:
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) {
let seen = new Set();
return a.filter(item => {
let k = key(item);
return seen.has(k) ? false : seen.add(k);
});
}
или Map
:
function uniqBy(a, key) {
return [
...new Map(
a.map(x => [key(x), x])
).values()
]
}
которые также работают с не примитивными ключами.
При удалении объектов по ключу может потребоваться оставить первый из "равных" объектов или последний.
Используйте описанный выше вариант Set
, чтобы сохранить первое, и Map
, чтобы сохранить последнее:
function uniqByKeepFirst(a, key) {
let seen = new Set();
return a.filter(item => {
let k = key(item);
return seen.has(k) ? false : seen.add(k);
});
}
function uniqByKeepLast(a, key) {
return [
...new Map(
a.map(x => [key(x), x])
).values()
]
}
//
data = [
{a:1, u:1},
{a:2, u:2},
{a:3, u:3},
{a:4, u:1},
{a:5, u:2},
{a:6, u:3},
];
console.log(uniqByKeepFirst(data, it => it.u))
console.log(uniqByKeepLast(data, it => it.u))
Надоело видеть все плохие примеры с помощью for-loops или jQuery. Javascript имеет идеальные инструменты для этого в наши дни: сортировка, карта и сокращение.
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;},[]);
В 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: удаление дубликатов с использованием объекта, такого как Set
Вы всегда можете попробовать поместить его в объект, а затем повторить его ключи:
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"]
Это библиотека с множеством функций для управления массивами.
Это связь с jQuery tux и Backbone.js подвесы.
_.uniq(array, [isSorted], [iterator])
Псевдоним: уникальный
Производит дублируемую версию массива , используя === для тестирования объекта равенство. Если вы заранее знаете, что массив сортируется, передавая true для isSorted будет работать гораздо быстрее алгоритм. Если ты хочешь вычислить уникальные элементы на основе преобразования, передать итераторфункция.
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
alert(_.uniq(names, false));
Примечание: Lo-Dash (участник underscore) также предлагает сопоставимый . uniq.
Версия с одной строкой с использованием фильтра массива и функций indexOf:
arr = arr.filter (function (value, index, array) {
return array.indexOf (value) == index;
});
Вы можете просто сделать это в JavaScript, с помощью второго - индекс - параметра метода 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)
Одна строка:
let names = ['Mike','Matt','Nancy','Adam','Jenny','Nancy','Carl', 'Nancy'];
let dup = [...new Set(names)];
console.log(dup);
Самый сжатый способ удаления дубликатов из массива с использованием собственных функций 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)]
ура!
используйте
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);
Идем для этого:
var uniqueArray = duplicateArray.filter(function(elem, pos) {
return duplicateArray.indexOf(elem) == pos;
});
Теперь uniqueArray не содержит дубликатов.
Самый простой, с которым я столкнулся. В es6.
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
Я сделал подробное сравнение удаления дубликатов по какому-то другому вопросу, но, заметив, что это реальное место, я просто хотел поделиться им здесь.
Я считаю, что это лучший способ сделать это
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);
Решение 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 намного быстрее!
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");
Ниже более чем на 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 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]);
}
}
В ECMAScript 6 (иначе ECMAScript 2015) Set
можно использовать для фильтрации дубликатов. Затем его можно преобразовать обратно в массив с помощью оператора spread.
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"],
unique = [...new Set(names)];
Лучшие ответы имеют сложность 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;
});
}
Это будет работать для строк, чисел и дат. Если ваш массив содержит объекты, приведенное выше решение не будет работать, поскольку при приведении к строке все они будут иметь значение "[object Object]"
(или что-то подобное), и это не подходит в качестве значения поиска. Вы можете получить реализацию 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;
}
Редакция 2019 года: Современные версии JavaScript значительно облегчают решение этой проблемы. Использование Set
будет работать независимо от того, содержит ли ваш массив объекты, строки, числа или любой другой тип.
function getDistinctArray(arr) {
return [...new Set(arr)];
}
Реализация настолько проста, что определение функции больше не требуется.
Простым, но эффективным методом является использование метода 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>';
Итак, параметры:
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, поэтому, если вам нужно идти ниже этого, вам нужно искать в другом месте.
Вы также можете использовать метод Array.unique()
из библиотека JavaScript Lab - или украсть идею оттуда.
Однако код там не очень хорошо написан, так как он объявляет метод unique()
как свойство прототипа Array, добавляя его к каждому массиву, нарушая функциональность for...in
(поскольку цикл for...in
всегда перебирайте и переменную unique
).
Вот общий и строго функциональный подход с 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) );
Здесь очень просто для понимания и работы в любом месте (даже в 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"]
for (i=0; i<originalArray.length; i++) {
if (!newArray.includes(originalArray[i])) {
newArray.push(originalArray[i]);
}
}
Небольшое изменение превосходного ответа 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);
});
}
$(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);
});
Если вы случайно использовали
D3.js
Вы могли бы сделать
d3.set(["foo", "bar", "foo", "baz"]).values() ==> ["foo", "bar", "baz"]
Это, вероятно, один из самых быстрых способов удаления навсегда дубликатов из массива В 10 раз быстрее, чем большинство функций здесь. & 78x быстрее в сафари
function toUnique(a,b,c){ //array,placeholder,placeholder
b=a.length;while(c=--b)while(c--)a[b]!==a[c]||a.splice(c,1)
}
если вы не можете прочитать приведенный выше код, прочитайте javascript книгу или вот некоторые объяснения относительно более короткого кода. fooobar.com/info/1682/...