2013-02-19 65 views
5

我有兩個數組,舊的和新的,它們在每個位置都有對象。我將如何同步或找到增量(即什麼是新的,更新和新的陣列中刪除較舊的陣列)JavaScript同步兩個數組(對象)/查找增量

var o = [ 
    {id:1, title:"title 1", type:"foo"}, 
    {id:2, title:"title 2", type:"foo"}, 
    {id:3, title:"title 3", type:"foo"} 
]; 

var n = [ 
    {id:1, title:"title 1", type:"foo"}, 
    {id:2, title:"title updated", type:"foo"}, 
    {id:4, title:"title 4", type:"foo"} 
]; 

通過上述數據,使用ID作爲關鍵,我們會發現, id = 2的項目有更新的標題,id = 3的項目被刪除,id = 4的項目是新的。

是否有一個現有的庫,有有用的功能,或者它是一個循環和內部循環的情況下,比較每一行..例如。

for(var i=0, l=o.length; i<l; i++) 
{ 
    for(var x=0, ln=n.length; x<ln; x++) 
    { 
     //compare when o[i].id == n[x].id  
    } 
} 

做這種比較三次,找到新的,更新和刪除?

+1

你可以加快速度一點,如果ID是唯一的,你使用一個對象與ID作爲關鍵。 – Sirko 2013-02-19 20:03:16

+0

你應該解釋什麼是輸出?具有三個屬性的對象? '{added:4],changed:[2],deleted:[3]}' – 2013-02-19 20:05:32

+0

輸出可能是三個陣列中最好的。刪除將只需要ID,添加和更改將需要完整的「行」/對象 – Fergal 2013-02-19 20:07:40

回答

12

沒有什麼魔法可以滿足您的需求。您需要遍歷這兩個對象以查找更改。一個好的建議是把你的結構變成地圖以加快搜索速度。

/** 
* Creates a map out of an array be choosing what property to key by 
* @param {object[]} array Array that will be converted into a map 
* @param {string} prop Name of property to key by 
* @return {object} The mapped array. Example: 
*  mapFromArray([{a:1,b:2}, {a:3,b:4}], 'a') 
*  returns {1: {a:1,b:2}, 3: {a:3,b:4}} 
*/ 
function mapFromArray(array, prop) { 
    var map = {}; 
    for (var i=0; i < array.length; i++) { 
     map[ array[i][prop] ] = array[i]; 
    } 
    return map; 
} 

function isEqual(a, b) { 
    return a.title === b.title && a.type === b.type; 
} 

/** 
* @param {object[]} o old array of objects 
* @param {object[]} n new array of objects 
* @param {object} An object with changes 
*/ 
function getDelta(o, n, comparator) { 
    var delta = { 
     added: [], 
     deleted: [], 
     changed: [] 
    }; 
    var mapO = mapFromArray(o, 'id'); 
    var mapN = mapFromArray(n, 'id');  
    for (var id in mapO) { 
     if (!mapN.hasOwnProperty(id)) { 
      delta.deleted.push(mapO[id]); 
     } else if (!comparator(mapN[id], mapO[id])){ 
      delta.changed.push(mapN[id]); 
     } 
    } 

    for (var id in mapN) { 
     if (!mapO.hasOwnProperty(id)) { 
      delta.added.push(mapN[id]) 
     } 
    } 
    return delta; 
} 

// Call it like 
var delta = getDelta(o,n, isEqual); 

爲例

+0

謝謝,救了我不得不認真考慮;) – Fergal 2013-02-19 20:52:26

+1

@Fergal這不是一件好事,對你來說最好的辦法就是自己嘗試一下,然後問你是否無法正常工作。如果你能得到它的工作,但想要的建議,那麼你可以問問http://codereview.stackexchange.com/ – 2013-02-19 20:54:38

+1

嗯,我有點開玩笑。我確實嘗試並主要工作(需要更多的幾行),同時關注此頁面。但是將數組轉換爲對象的方式確實減少了代碼行(使用hasOwnProperty) – Fergal 2013-02-19 21:01:00

0

http://jsfiddle.net/wjdZ6/1/這是@Juan Mendes答案的打字稿版本

mapFromArray(array: Array<any>, prop: string): { [index: number]: any } { 
    const map = {}; 
    for (let i = 0; i < array.length; i++) { 
     map[array[i][prop]] = array[i]; 
    } 
    return map; 
    } 

    isEqual(a, b): boolean { 
    return a.title === b.title && a.type === b.type; 
    } 

    getDelta(o: Array<any>, n: Array<any>, comparator: (a, b) => boolean): { added: Array<any>, deleted: Array<any>, changed: Array<any> } { 
    const delta = { 
     added: [], 
     deleted: [], 
     changed: [] 
    }; 
    const mapO = this.mapFromArray(o, 'id'); 
    const mapN = this.mapFromArray(n, 'id'); 
    for (const id in mapO) { 
     if (!mapN.hasOwnProperty(id)) { 
     delta.deleted.push(mapO[id]); 
     } else if (!comparator(mapN[id], mapO[id])) { 
     delta.changed.push(mapN[id]); 
     } 
    } 

    for (const id in mapN) { 
     if (!mapO.hasOwnProperty(id)) { 
     delta.added.push(mapN[id]); 
     } 
    } 
    return delta; 
    }