Получите все уникальные значения в массиве 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;
}
Дополнительные ответы от дублирующего вопроса:
Аналогичный вопрос:
Ответы
Ответ 1
С 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 за намек в комментарии.
Ответ 2
Обновленный ответ для 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)]
Ответ 3
Я понимаю, что этот вопрос уже содержит более 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 для кода.
Ответ 4
Вы также можете использовать underscore.js.
console.log(_.uniq([1, 2, 1, 3, 1, 4]));
<script src="http://underscorejs.org/underscore-min.js"></script>
Ответ 5
Один лайнер, чистый 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 +
Ответ 6
С тех пор я нашел хороший метод, который использует jQuery
arr = $.grep(arr, function(v, k){
return $.inArray(v ,arr) === k;
});
Примечание: этот код был вытащен из Paul Irish duck punching post - Я забыл отдать должное: P
Ответ 7
Самое короткое решение с 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:
Ответ 8
Самое простое решение:
var arr = [1, 3, 4, 1, 2, 1, 3, 3, 4, 1];
console.log([...new Set(arr)]);
Ответ 9
Самый простой и самый быстрый (в 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;
}
Это также быстрее, чем описанный выше метод в большинстве браузеров без хрома.
Ответ 10
ТОЛЬКО ПРОИЗВОДИТЕЛЬНОСТЬ! этот код, вероятно, на 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]
Ответ 11
Многие из ответов здесь могут быть бесполезны для начинающих. Если дедупликация массива затруднена, они действительно будут знать о цепочке прототипов или даже 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)
становится тем, что мы назвали результатом, когда функция завершается.
Просто передайте ему имя любого массива, который вам нравится.
Ответ 12
["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;
}, []);
Ответ 13
Этот прототип 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"]
.
Ответ 14
Мы можем сделать это, используя наборы ES6:
var duplicatedArray = [1, 2, 3, 4, 5, 1, 1, 1, 2, 3, 4];
var uniqueArray = Array.from(new Set(duplicatedArray));
console.log(uniqueArray);
Ответ 15
Без расширения 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,...).
Ответ 16
магия
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) ))
Ответ 17
Если вы используете Prototype framework, вам не нужно делать "для" циклов, вы можете использовать http://www.prototypejs.org/api/array/uniq следующим образом:
var a = Array.uniq();
Будет создан дублированный массив без дубликатов. Я наткнулся на ваш вопрос, ища метод для подсчета различных записей массивов, поэтому после
Uniq()
Я использовал
размер()
и был мой простой результат.
постскриптум Извините, если я что-то испортил.
edit: если вы хотите избежать записи undefined, вы можете добавить
compact()
раньше, например:
var a = Array.compact().uniq();
Ответ 18
Это потому, что 0
является фальшивым значением в JavaScript.
this[i]
будет ложным, если значение массива равно 0 или любое другое значение фальши.
Ответ 19
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
}
Ответ 20
[...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]
Ответ 21
У меня была немного другая проблема, когда мне нужно было удалить объекты с дублирующимися свойствами идентификатора из массива. это сработало.
let objArr = [{
id: '123'
}, {
id: '123'
}, {
id: '456'
}];
objArr = objArr.reduce((acc, cur) => [
...acc.filter((obj) => obj.id !== cur.id), cur
], []);
console.log(objArr);
Ответ 22
Из блог Шамаси Бхаттачарья (сложность времени 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]
Ответ 23
Я не уверен, почему Габриэль Сильвейра написала эту функцию таким образом, но более простая форма, которая работает для меня так же хорошо, и без минимизации:
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
)
Ответ 24
Поиск уникальных значений массива в простом методе
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]
Ответ 25
странно, что это не предлагалось раньше. Чтобы удалить дубликаты с помощью ключа объекта (id
ниже) в массиве, вы можете сделать что-то вроде этого:
const uniqArray = array.filter((obj, idx, arr) => (
arr.findIndex((o) => o.id === obj.id) === idx
))
Ответ 26
с es6 (и поддерживает порядок):
[...new Set(myArray)];
Ответ 27
Теперь с помощью наборов вы можете удалять дубликаты и преобразовывать их обратно в массив.
var names = ["Mike","Matt","Nancy", "Matt","Adam","Jenny","Nancy","Carl"];
console.log([...new Set(names)])
Ответ 28
Похоже, мы потеряли ответ рафаэля, который считался принятым ответом в течение нескольких лет. Это было (по крайней мере, в 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;
}
Ответ 29
Чтобы решить проблему, наоборот, может быть полезно иметь дубликат при загрузке массива, способ 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]
Ответ 30
Сделайте набор массива, а затем инициализируйте мелкую копию набора в нужном контейнере.
let array = [1,2,3,2,1];
let uniqueArray = [... new Set(array)];