2013-10-21 128 views
18

我想弄清楚一個有效的方法來刪除從數組中重複的對象並尋找最有效的答案。我環顧了互聯網,似乎一切似乎都在使用原始數據......或者對於大型數組不可伸縮。這是我現在可以改進的實現,並且想要避免使用標籤。使用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請沒有庫。

到目前爲止的答案:

下面的答案性能測試: http://jsperf.com/remove-duplicates-for-loops

+0

是你的_Objects_安全爲_JSON_? 「串化」它們並比較它可能是最快的。 **編輯**這可能不是最適合你的,因爲只有當屬性按照相同的順序定義時纔有效。 –

+0

也許這個問題:http://stackoverflow.com/questions/3629817/getting-a-union-of-two-arrays-in-javascript –

+0

你是什麼意思「試圖處理超過1000個結果時失敗」 ?怎麼了? – mayabelle

回答

30

我看,問題存在的複雜性平方。有一個技巧可以做到,只需使用「關聯數組」即可。

您可以獲取數組,循環它並將該數組的值作爲關鍵字添加到關聯數組中。由於它不允許重複鍵,因此您將自動刪除重複項。

既然你正在尋找的標題和比較,當藝術家,實際上你可以嘗試使用類似:

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的評論。謝謝!

+1

'arrResult'這裏是一個普通的_Object_。你還需要一個分隔符來保護'foo,bar'免受'foob,ar'的攻擊。 +1,因爲這對OP的情況應該很好用 –

+0

不要忘記在循環之前聲明'arrResult',並在內部使用arr [i]而不是arr。 –

+0

這不起作用...看看這個簡單的例子http://jsfiddle.net/yKwZe/ – Lion789

2

基本排序當時唯一實現,小提琴HERE

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; 
+0

您可以檢查http://stackoverflow.com/questions/234683/javascript-array-sort-implementation/236534#236534對典型的'sort'複雜的信息。這顯然做了一個額外的線性傳遞,使其獨特,並不公然地佔用任何額外的空間。 –

+0

這似乎是工作,但它實際上是由一個... http://jsfiddle.net/9GsCw/1/ – Lion789

+1

@ Lion789我同意。我確實提出了恩裏克的答案,即O(n),但認爲將它留在我身邊不會有什麼傷害。這可能對其他某些人有所幫助。 –

0

下面的代碼使用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 
    }) 
+0

我明白爲什麼沒有人真正嘗試過使用它。或者至少給一些反饋 – Jay

1

我使用這個函數。它沒有做任何排序,但產生的結果。無法評價性能,因爲從來沒有衡量它。

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」]所有獨特的元素。

0
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; 
} 
+0

可以做一些解釋... – user1578653

+0

這是使用jquery,man ... –

+0

O(N^2)使小貓哭泣。 – Alexander

3

這是一個適合我的解決方案。

輔助功能:

// 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

我是這個解決方案的粉絲。謝謝! – DrewT

0

下面是恩裏克費若的回答了充足的解釋,你可以剪切和粘貼的例子:

目標:轉換包含重複對象的對象數組(如此一)...

[ 
    { 
     "id": 10620, 
     "name": "Things to Print" 
    }, 
    { 
     "id": 10620, 
     "name": "Things to Print" 
    }, 
    { 
     "id": 4334, 
     "name": "Interesting" 
    } 
] 

... INTO對象的數組沒有重複的對象(像這樣):

[ 
    { 
     "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)