Удаление повторяющихся объектов из массива с помощью javascript
Я пытаюсь найти эффективный способ удаления объектов, которые являются дубликатами из массива, и ищет наиболее эффективный ответ. Я огляделся по всему интернету, все, кажется, использует примитивные данные... или не масштабируется для больших массивов. Это моя текущая реализация, которая может быть улучшена и вы хотите попытаться избежать ярлыков.
Test.prototype.unique = function (arr, artist, title, cb) {
console.log(arr.length);
var n, y, x, i, r;
r = [];
o: for (i = 0, n = arr.length; i < n; i++) {
for (x = 0, y = r.length; x < y; x++) {
if (r[x].artist == arr[i].artist && r[x].title == arr[i].title) {
continue o;
}
}
r.push(arr[i]);
}
cb(r);
};
и массив выглядит примерно так:
[{title: sky, artist: jon}, {title: rain, artist: Paul}, ....]
Заказ не имеет значения, но если сортировка делает его более эффективным, я решаю проблему...
и для людей, которые не знают o, является меткой, и это просто говорит о возврате к циклу, а не к нажатию на новый массив.
Чистый javascript, пожалуйста, нет libs.
ОТВЕТЫ ТАК ДАЛЬШЕ:
Тест производительности для ответов ниже:
http://jsperf.com/remove-duplicates-for-loops
Ответы
Ответ 1
Я вижу, проблема в том, что сложность квадрата. Для этого есть один трюк, просто используя "Ассоциативные массивы".
Вы можете получить массив, перебрать его и добавить значение массива в качестве ключа к ассоциативному массиву. Поскольку он не позволяет дублировать ключи, вы автоматически избавитесь от дубликатов.
Поскольку вы ищете для названия и исполнителя при сравнении, вы можете попытаться использовать что-то вроде:
var arrResult = {};
for (i = 0, n = arr.length; i < n; i++) {
var item = arr[i];
arrResult[ item.title + " - " + item.artist ] = item;
}
Затем вы снова зацикливаете arrResult и воссоздаете массив.
var i = 0;
var nonDuplicatedArray = [];
for(var item in arrResult) {
nonDuplicatedArray[i++] = arrResult[item];
}
Обновлен, чтобы включить комментарий Paul. Спасибо!
Ответ 2
Вот решение, которое работает для меня.
Вспомогательные функции:
// sorts an array of objects according to one field
// call like this: sortObjArray(myArray, "name" );
// it will modify the input array
sortObjArray = function(arr, field) {
arr.sort(
function compare(a,b) {
if (a[field] < b[field])
return -1;
if (a[field] > b[field])
return 1;
return 0;
}
);
}
// call like this: uniqueDishes = removeDuplicatesFromObjArray(dishes, "dishName");
// it will NOT modify the input array
// input array MUST be sorted by the same field (asc or desc doesn't matter)
removeDuplicatesFromObjArray = function(arr, field) {
var u = [];
arr.reduce(function (a, b) {
if (a[field] !== b[field]) u.push(b);
return b;
}, []);
return u;
}
а затем просто вызовите:
sortObjArray(dishes, "name");
dishes = removeDuplicatesFromObjArray(dishes, "name");
Ответ 3
Основная сортировка-уникальная реализация, скрипка ЗДЕСЬ:
function unique(arr) {
var comparer = function compareObject(a, b) {
if (a.title == b.title) {
if (a.artist < b.artist) {
return -1;
} else if (a.artist > b.artist) {
return 1;
} else {
return 0;
}
} else {
if (a.title < b.title) {
return -1;
} else {
return 1;
}
}
}
arr.sort(comparer);
console.log("Sorted: " + JSON.stringify(arr));
for (var i = 0; i < arr.length - 1; ++i) {
if (comparer(arr[i], arr[i+1]) === 0) {
arr.splice(i, 1);
console.log("Splicing: " + JSON.stringify(arr));
}
}
return arr;
}
Он может быть или не быть наиболее эффективным и должен быть полностью масштабируемым. Я добавил несколько console.log
, чтобы вы могли видеть, как он работает.
ИЗМЕНИТЬ
В интересах сохранения в пространстве используемой функции я сделал цикл for
в конце, но, похоже, он не нашел правильных результатов только для уникальных результатов (depsite передал мой простой тест jsfiddle). Попробуйте заменить мой цикл for
следующим образом:
var checker;
var uniqueResults = [];
for (var i = 0; i < arr.length; ++i) {
if (!checker || comparer(checker, arr[i]) != 0) {
checker = arr[i];
uniqueResults.push(checker);
}
}
return uniqueResults;
Ответ 4
Я использую эту функцию. он не делает никакой сортировки, но дает результат. Не могу сказать о производительности, так как никогда не измеряйте ее.
var unique = function(a){
var seen = [], result = [];
for(var len = a.length, i = len-1; i >= 0; i--){
if(!seen[a[i]]){
seen[a[i]] = true;
result.push(a[i]);
}
}
return result;
}
var ar = [1,2,3,1,1,1,1,1, "," ", "," "," a "," b"];
console.log(unique (ar));//это создаст [1,2,3, "," a "," b"] все уникальные элементы.
Ответ 5
Ниже Henrique Feijo ответ с широким объяснением и примером, который вы можете вырезать и вставить:
Цель: преобразовать массив объектов, содержащих повторяющиеся объекты (например, этот)...
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
... В массив объектов без повторяющихся объектов (например, этот):
[
{
"id": 10620,
"name": "Things to Print"
},
{
"id": 4334,
"name": "Interesting"
}
]
Объяснение приведено в комментариях:
var allContent = [{
"id": 10620,
"name": "Things to Print"
}, {
"id": 10620,
"name": "Things to Print"
}, {
"id": 4334,
"name": "Interesting"
}]
//Put Objects Into As Associative Array. Each key consists of a composite value generated by each set of values from the objects in allContent.
var noDupeObj = {} //Create an associative array. It will not accept duplicate keys.
for (i = 0, n = allContent.length; i < n; i++) {
var item = allContent[i]; //Store each object as a variable. This helps with clarity in the next line.
noDupeObj[item.id + "|" + item.name] = item; //This is the critical step.
//Here, you create an object within the associative array that has a key composed of the two values from the original object.
// Use a delimiter to not have foo+bar handled like fo+obar
//Since the associative array will not allow duplicate keys, and the keys are determined by the content, then all duplicate content are removed.
//The value assigned to each key is the original object which is along for the ride and used to reconstruct the list in the next step.
}
//Recontructs the list with only the unique objects left in the doDupeObj associative array
var i = 0;
var nonDuplicatedArray = [];
for (var item in noDupeObj) {
nonDuplicatedArray[i++] = noDupeObj[item]; //Populate the array with the values from the noDupeObj.
}
console.log(nonDuplicatedArray)
Ответ 6
Ниже код сравнивает объект с JSON как строковый формат и удаляет дубликаты и отлично работает с простыми массивами.
Array.prototype.unique=function(a){
return function(){
return this.filter(a)
}
}(
function(a,b,c){
var tmp=[];
c.forEach(function(el){
tmp.push(JSON.stringify(el))
});
return tmp.indexOf(JSON.stringify(a),b+1)<0
})
Ответ 7
Если вы используете символ подчеркивания js, легко удалить дублированный объект.
http://underscorejs.org/#uniq
Ответ 8
function remove_duplicates(objectsArray) {
var arr = [], collection = [];
$.each(objectsArray, function (index, value) {
if ($.inArray(value.id, arr) == -1) {
arr.push(value.id);
collection.push(value);
}
});
return collection;
}
Ответ 9
Для тех, кто любит ES6 и короткие вещи, вот одно решение:
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" }
];
Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
const arr = [
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Paul" },
{ title: "sky", artist: "Jon" },
{ title: "rain", artist: "Jon" },
{ title: "cry", artist: "Jon" }
];
const unique = Array.from(arr.reduce((a, o) => a.set(o.title, o), new Map()).values());
console.log('New array length: ${unique.length}')
console.log(unique)