2013-02-19 10 views
5

Mam dwie tablice, stare i nowe, które przechowują obiekty w każdej pozycji. Jak zsynchronizować lub znaleźć Delta (czyli to, co jest nowe, zaktualizowane i usunięte z nowej tablicy w porównaniu do starej tablicy)Synchronizacja JavaScript dwie tablice (obiektów)/znajdź deltę

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

Z powyższych danych, używając identyfikatora jako klucz, by stwierdzić, że mamy item z id = 2 ma zaktualizowany tytuł, element o id = 3 został usunięty, a element o id = 4 jest nowy.

Czy istnieje istniejąca biblioteka, która ma przydatne funkcje, czy jest to przypadek pętli i wewnętrznej pętli, porównaj każdy wiersz ... .eu.

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

Czy dokonujesz tego rodzaju porównania trzy razy, aby znaleźć nowe, zaktualizowane i usunięte?

+1

Można przyspieszyć trochę, jeśli Identyfikatory są unikalne i użyć obiektu z identyfikatorem jako klucze. – Sirko

+0

Powinieneś wyjaśnić, co jest wynikiem? Obiekt z trzema właściwościami? '{added: 4], zmieniono: [2], usunięto: [3]}' –

+0

Dane wyjściowe będą prawdopodobnie najlepsze w trzech tablicach. Usunięty będzie potrzebował tylko identyfikatorów, dodane i zmienione wymagałoby pełnego "wiersza"/obiektu – Fergal

Odpowiedz

12

Nie ma magii, aby robić to, czego potrzebujesz. Musisz przejrzeć oba obiekty, szukając zmian. Dobrą sugestią jest przekształcenie struktury w mapy w celu szybszego wyszukiwania.

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

Zobacz http://jsfiddle.net/wjdZ6/1/ na przykład

+0

Dzięki, oszczędza mi to, że muszę myśleć zbyt mocno;) – Fergal

+1

@Fergal To nie jest dobra rzecz, lepiej byłoby spróbować samemu, a następnie zadawać pytania, jeśli nie można go uruchomić. Jeśli możesz go uruchomić, ale potrzebujesz sugestii, możesz zapytać na http://codereview.stackexchange.com/ –

+1

Cóż, trochę żartowałem. Starałem się, aby działał głównie (potrzebuję jeszcze kilku linii), jednocześnie obserwując tę ​​stronę. Ale sposób konwersji tablic na obiekty naprawdę zmniejszył linie kodu (używając hasOwnProperty) – Fergal

0

To jest wersja maszynopis @Juan Mendes odpowiedź

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; 
    } 
Powiązane problemy