2017-06-21 61 views
1

如果我有這樣一個數組:如何刪除在對象數組中出現多次的任何對象?

[ 
    { 
     id: 1, 
     title: 'foo' 
    }, 
    { 
     id: 2, 
     title: 'bar' 
    }, 
    { 
     id: 3, 
     title: 'bat' 
    }, 
    { 
     id: 4, 
     title: 'bantz' 
    }, 
    { 
     id: 2, 
     title: 'bar' 
    }, 
    { 
     id: 3, 
     title: 'bat' 
    } 
] 

而且我想返回一個包含只出現一次的所有對象的數組。所以,在這個例子中,所需的輸出將是:

[ 
    { 
     id: 1, 
     title: 'foo' 
    }, 
    { 
     id: 4, 
     title: 'bantz' 
    } 
] 

我已經試過,我發現這個使用reduce()indexOf(),像this的解決方案,解決了幾種不同的方法,但他們不爲對象的工作一些原因。

任何援助將不勝感激。

+0

所有這些對象都是不同的;從你發佈的內容來看,*沒有*它們真的是重複的。你可能有自己的標準是什麼使兩個物體相同; 「ID」是否相等? 「id」和「title」? – Pointy

+0

它們將是具有所有相同的鍵和值的對象。我不明白你的評論。 {id:2,title:bar}如何不是{id:2,title:bar}的副本?它們具有完全相同的密鑰和值。 編輯:我只是注意到我列爲期望的結果是錯誤的。我現在編輯它。 –

+0

@MattGween Pointy解釋了爲什麼使用indexOf的解決方案失敗。 '{}!= {}'因爲儘管它們具有相同的鍵和值,但它們是兩個單獨的對象。 – Paulpro

回答

3

您可以使用Map來避免一次又一次地查看數組,這將導致時間複雜度較低的O(n²)。這是O(n)的

function getUniquesOnly(data) { 
 
    return Array.from(
 
     data.reduce((acc, o) => acc.set(o.id, acc.has(o.id) ? 0 : o), new Map), 
 
     (([k,v]) => v) 
 
    ).filter(x => x); 
 
} 
 

 
var data = [ 
 
    { 
 
     id: 1, 
 
     title: 'foo' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    }, 
 
    { 
 
     id: 4, 
 
     title: 'bantz' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    } 
 
]; 
 

 
console.log(getUniquesOnly(data));

3

做這樣的事情:

const data = [ 
 
    { 
 
     id: 1, 
 
     title: 'foo' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    }, 
 
    { 
 
     id: 4, 
 
     title: 'bantz' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    } 
 
]; 
 

 
const isEqual = (a, b) => a.id === b.id; 
 
const unique = (arr) => arr.reduce((result, a, index) => 
 
    result.concat(arr.some(b => a !== b && isEqual(a, b)) ? [] : a) 
 
, []); 
 

 
console.log(unique(data));

在這種情況下,我們遍歷每個元素reduce(),在此之前我們添加它,我們看看它的另一個版本中存在數組添加之前。我們必須確保,如果沒有我們自己,我們也不會平等(否則我們會得到一個空陣列)。

isEqual()是一個獨立的功能,可以很容易地定製「平等」的含義。

正如所寫,data中的每個元素都是唯一的,它們都是獨立的對象。 data[0] === data[4]false,即使它們具有相同的數據。您必須比較內部數據以確定它們是否重複。正如Paulpro之前提到的,{} === {}也是false,因爲它們是兩個不同的對象,即使它們的值相同。

console.log({} === {}); 
 
console.log({ a: 1 } === { a: 1 });

isEqual()的例子版本,我認爲他們是平等的,如果他們有相同的ID。


回答到以前版本的問題

的做這樣的事情:

const data = [ 
 
    { 
 
     id: 1, 
 
     title: 'foo' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    }, 
 
    { 
 
     id: 4, 
 
     title: 'bantz' 
 
    }, 
 
    { 
 
     id: 2, 
 
     title: 'bar' 
 
    }, 
 
    { 
 
     id: 3, 
 
     title: 'bat' 
 
    } 
 
]; 
 

 
const isEqual = (a, b) => a.id === b.id; 
 
const unique = (arr) => arr.reduce((result, a) => 
 
    result.concat(result.some(b => isEqual(a, b)) ? [] : a) 
 
, []); 
 

 
console.log(unique(data));

我分裂isEqual()到它自己的功能,所以你可以很容易地定義什麼是「平等「的意思。正如有人指出的那樣,從技術上講,所有這些都是獨一無二的,即使數據不同。在我的例子中,我定義了相等的ID,意味着平等。

然後我使用reduce來遍歷每個對象並構建一個對象。在我將它添加到數組之前(通過concat()),我通過some()循環所有這些數組,直到找到一個相等的(我不會包含的)或者沒有一個相等,然後添加它。

+0

原始問題已被顯着改變 – mhodges

+1

@mhodges確實。我調整了我的答案以符合新的要求。 – samanime

0

直接實現會是這個樣子:

  • 創建一個空集(在這種情況下,數組)包含(IE 深層比較或通過像「ID」這樣的唯一值進行比較)的唯一值
  • 遍歷值的列表
  • 無論何時你發現沒有包含該組唯一值的中值,添加它

這基本上是你如何解決發佈的作品,除了所有的你的數組中的值 - 在JavaScript的眼中 - 是唯一的。正因爲如此,你需要定義自己的方式來比較值。

的。降低方法可用於像這樣:

function areEqual(a, b) { /* define how you want the objects compared here */ } 

function contains(a, lst) { 
    return lst.reduce(function (acc, x) { 
     return acc || areEqual(a, x); 
    }, false); 
} 

function getUnique(lst) { 
    return lst.reduce(function (acc, x) { 
     if(!contains(x, acc)) 
     { 
      acc.push(x); 
     } 

     return acc; 
    }, []); 
} 

你可能想看看JavaScript對象比較是如何工作的。爲了深入比較(這聽起來像你想),我會看看existing answers