2013-02-19 23 views
5

Tôi có hai mảng, cũ và mới, giữ đối tượng ở mỗi vị trí. Làm thế nào tôi có thể đồng bộ hóa hoặc tìm đồng bằng (tức là những gì đang mới, cập nhật và xóa khỏi mảng mới so với các mảng cũ)JavaScript đồng bộ hai mảng (của đối tượng)/tìm delta

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"} 
]; 

Với các dữ liệu trên, sử dụng id như chìa khóa, chúng tôi thấy rằng mục có id = 2 có tiêu đề cập nhật, mục có id = 3 bị xóa và mục có id = 4 là mới.

Có thư viện hiện có ở đó có chức năng hữu ích hay không hoặc là trường hợp vòng lặp và vòng lặp bên trong, so sánh từng hàng..ví dụ.

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

Thực hiện loại so sánh này ba lần, để tìm mới, cập nhật và xóa?

+1

Bạn có thể điều tốc độ lên một chút, nếu id là duy nhất và bạn sử dụng một đối tượng với id như là chìa khóa. – Sirko

+0

Bạn nên giải thích đầu ra là gì? Một đối tượng có ba thuộc tính? '{added: 4], changed: [2], deleted: [3]}' –

+0

Đầu ra có thể là tốt nhất trong ba mảng. Các xóa sẽ chỉ cần ID, thêm và thay đổi sẽ cần đầy đủ "hàng"/đối tượng – Fergal

Trả lời

12

Không có phép thuật nào để làm những gì bạn cần. Bạn cần phải lặp qua cả hai đối tượng tìm kiếm các thay đổi. Một gợi ý tốt là chuyển cấu trúc của bạn thành bản đồ để tìm kiếm nhanh hơn.

/** 
* 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); 

Xem http://jsfiddle.net/wjdZ6/1/ cho một ví dụ

+0

Cảm ơn, giúp tôi phải suy nghĩ quá nhiều;) – Fergal

+1

@Fergal Đó không phải là một điều tốt, điều tốt hơn để bạn có thể thử nó một mình, và sau đó đặt câu hỏi nếu bạn không thể làm cho nó hoạt động. Nếu bạn có thể làm cho nó hoạt động nhưng muốn có đề xuất, thì bạn có thể hỏi tại http://codereview.stackexchange.com/ –

+1

Vâng, tôi đã nói đùa. Tôi đã cố gắng và nhận được nó làm việc chủ yếu (một vài dòng yêu cầu là tất cả) trong khi giữ một mắt trên trang này. Nhưng cách bạn chuyển đổi mảng thành các đối tượng thực sự làm giảm các dòng mã (sử dụng hasOwnProperty) – Fergal

0

Đây là phiên bản nguyên cảo của @Juan Mendes câu trả lời

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