2016-03-21 13 views
5

Poniżej znajdują się moje dwie tablice. Chcę je porównać, a wynikowa tablica powinna zawierać zaktualizowane wartości. Są one wspólne .. Tablice obejmują n poziomach, tj., że nie ma stałego poziomu ..Porównaj dwie tablice i zaktualizuj nowe wartości, zachowując istniejące obiekty przy użyciu javascript

pierwsza tablica tzn. matryca przed updation ..

var parentArray1=[ 
    { 
     "id": 1, 
     "name": "test", 
     "context": [ 
      { 
       "id": 1.1, 
       "name": "test 1.1" 
      } 
     ] 
    }, 
    { 
     "id": 2, 
     "name": "test" 
    }, 
    { 
     "id": 3, 
     "name": "test", 
     "context": [ 
      { 
       "id": 3.1, 
       "name": "test 3.1" 
      } 
     ] 
    }, 
    { 
     "id": 4, 
     "name": "test" 
    } 
] 

że operacje wykonywane są

1.Adding nowy Pozycja 2.Upda ting istniejący element

W wyniku tych dwóch operacji zmienione wartości I będzie coraz w innej tablicy .. tzn.

var changedArray= 

     [ 
     { 
      "id": 1, 
      "name": "test1", 
      "context": [ 
       { 
        "id": 1.1, 
        "name": "Changed test 1.1" 
       } 
      ] 
     }, 
     { 
      "id": 5, 
      "name": "test5" 
     } 
    ] 

Teraz Pisałem rodzajowe funkcji, które przechodzi poprzez parentArray1 i stosując unikalne propertiesI trzeba dodać nowy element, jeśli element jest tam w changedArray lub zaktualizować istniejący element na każdym poziomie

Uzyskana tablica powinna być ..

[ 
    { 
     "id": 1, 
     "name": "test", 
     "context": [ 
      { 
       "id": 1.1, 
       "name": "Changed test 1.1" 
      } 
     ] 
    }, 
    { 
     "id": 2, 
     "name": "test" 
    }, 
    { 
     "id": 3, 
     "name": "test", 
     "context": [ 
      { 
       "id": 3.1, 
       "name": "test 3.1" 
      } 
     ] 
    }, 
    { 
     "id": 4, 
     "name": "test" 
    }, 
    { 
     "id": 5, 
     "name": "test5" 
    } 
] 

Generic funkcja:

compareArray(parentArray1, changedArray, ["id"]); 

     function compareArray(array1, array2, propertyArray) { 
      var newItem = new Array(); 
      array2.map(function(a1Item) { 
       array1.map(function(a2Item) { 
        /If array loop again/
        if (a2Item.constructor === Array) { 
         compareArray(a2Item, a1Item) 
        } else { 
         /loop the property name to validate/
         propertyArray.map(function(property) { 
          if (a2Item[property]) { 
           if (a2Item[property] === a1Item[property]) { 
            a2Item = a1Item 
           } else { 
            var isAvailable = _.find(newItem, function(item) { 
             return item[property] === a1Item[property] 
            }) 
            if (!isAvailable) { 
             newItem.push(a1Item); 
            } 
           } 
          } 
         }) 
        } 

       }); 
      }); 

      /Insert the new item into the source array/
      newItem.map(function(item) { 
       array1.push(item); 
      }); 
      console.log("After Compare : " + array1); 
     } 
+0

Kod, który udostępniasz, ma dodatkową funkcjonalność, jeśli element tablicy jest także tablicą. Czy chcesz to zachować? Załóżmy również, że masz coś takiego jak '{a: {b: 'value'}}' jako element w array2.Jeśli chcesz zaktualizować wartość a w oryginalnym obiekcie, czy chcesz go zaktualizować za pomocą '=', co oznacza, że ​​aktualizujesz jedynie odniesienia do obiektu, czy też chcesz sklonować wartość '{b: ' } 'obiekt i mieć inną instancję o tych samych wartościach? –

+0

W moim przypadku tablica jest zagnieżdżona z innymi właściwościami i jeśli wartością jest obiekt, powinniśmy sklonować. Jedynym identyfikatorem w tablicy jest nazwa właściwości tj.., Id's – forgottofly

+0

Myślę, że twoje pytanie jest zbyt skomplikowane, nie możesz dokładnie określić problem, który masz? Co nie działa tak, jak myślisz, powinno? – froginvasion

Odpowiedz

0

To właśnie wymyśliłem:

function sameKeys(o1, o2, keys) { 
    for (var i = 0; i < keys.length; i++) { 
     var key = keys[i]; 
     if (!o1.hasOwnProperty(key) || !o2.hasOwnProperty(key)) 
      throw 'compared objects do not have the key ' + key; 
     if (o1[key] !== o2[key]) 
      return false; 
    } 
    return true; 
} 

function isNothing(o) { 
    return typeof(o) === 'undefined' || o === null; 
} 

// this does not work if objects have functions as properties 
function clone(o) { 
    if (isNothing(o)) 
     return o; 
    return JSON.parse(JSON.stringify(o)); 
} 

function extend(o1, o2, keys) { 
    if (isNothing(o2)) 
     return; 
    if (isNothing(o1)) 
     throw ('first parameter cannot be empty'); 
    if (typeof(o1) != 'object' || typeof(o2) != 'object') 
     throw ('extend only works on objects'); 
    Object.keys(o2).forEach(function (key) { 
     var newVal = o2[key]; 
     if (o1.hasOwnProperty(key)) { 
      if (isNothing(newVal)) { 
       delete o1[key]; 
      } else 
       if (Array.isArray(newVal)) { 
        compareArray(o1[key], newVal, keys); 
       } else { 
        switch (typeof(newVal)) { 
        case 'object': 
         extend(o1[key], newVal, keys); 
         break; 
        case 'boolean': 
        case 'number': 
        case 'string': 
         o1[key] = newVal; 
         break; 
        default: 
         throw 'not supported property type: ' + typeof(newVal); 
        } 
       } 
     } else { 
      o1[key] = clone(newVal); 
     } 
    }); 
} 

function removeFromArray(arr, ids, keyArray) { 
    var indexes = []; 
    var it1s = arr.forEach(function (it, idx) { 
      if (sameKeys(ids, it, keyArray)) { 
       indexes.push(idx); 
      } else { 
       Object.keys(it).forEach(function (key) { 
        var newVal = it[key]; 
        if (Array.isArray(newVal)) { 
         removeFromArray(it[key], ids, keyArray); 
        } 
       }); 
      } 
     }); 
    if (indexes.length) { 
     if (indexes.length > 1) 
      throw 'found multiple possible objects for the same key combination' 
      arr.splice(indexes[0], 1); 
    } 
} 

function compareArray(a1, a2, keyArray) { 

    a2.forEach(function (it2) { 
     var it1s = a1.filter(function (it) { 
       return sameKeys(it2, it, keyArray); 
      }); 
     var it1; 
     if (!it1s.length) { 
      it1 = clone(it2); 
      a1.push(it1); 
     } else { 
      if (it1s.length > 1) 
       throw 'found multiple possible objects for the same key combination' 
       it1 = it1s[0]; 
      extend(it1, it2, keyArray); 
     } 
     if (it2.removedIds) { 
      it2.removedIds.forEach(function (ids) { 
       removeFromArray(a1, ids, keyArray); 
      }); 
     } 
    }); 

} 

Użyj go z compareArray(parentArray1,changedArray,['id']);

pamiętać, że nie będzie działać z obiektami, które zawierają funkcje. Ponadto, jeśli tablice byłyby duże, prawdopodobnie lepszym rozwiązaniem byłoby sortowanie obu tablic według klucza, a następnie zawsze wyglądać od ostatniego znalezionego obiektu w górę. To wszystko, na co mam teraz.

Zaktualizował go o kilka pojęć od Niny i pewne wyczyszczenie kodu.

Jak rozumiem, chcesz tylko dodać właściwości. Tak więc rozszerzenie ({a: {b: 2}}, {a: {c: 3}}) spowoduje {a: {b: 2, c: 3}}. Jeśli nie tego chciałeś, daj mi znać.

Dodałem także funkcję usuwania identyfikatorów. Jeśli którykolwiek z obiektów w tablicy zawiera tablicę removedIds w postaci [{id: 4},{id: 5}], elementy z tymi identyfikatorami zostaną usunięte z oryginalnej tablicy.

+0

pls sprawdź ten plunker https://plnkr.co/edit/KEZs1dWlJRWpMslC2pZL?p=preview dodałem nowa aktywność z activityId 23 Jej wyświetlanie, ale co z istniejącą aktywnością o identyfikatorze 22 – forgottofly

+0

W tym miejscu niektóre obiekty podrzędne nie mają identyfikatorów. Funkcja ta identyfikuje, że dwa obiekty bez klucza id mają ten sam klucz, a algorytm zajmuje tylko pierwszy. Nie wiem, jak chcesz, aby to działało: użyj jednego z kluczy kończących się identyfikatorem? Więc zamiast używać wszystkich kluczy w tablicy, użyj jednego z nich? Zaktualizowałem kod, aby wymagał kluczy wszystkich porównywanych obiektów i zgłaszał wyjątek, jeśli znaleziono więcej niż jedną pozycję dla tej samej kombinacji klawiszy. –

+0

Mam inne wymaganie, tak jakbym usunął obiekt w changedArray ie., { "id": 1.1, "name": "Zmieniony test 1.1" } Chcę to usunąć w parentArray1 po uruchomieniu funkcji compareArray .Jak mogę to zrobić. Proszę o poradę – forgottofly

1

Proponuję użyć tymczasowy obiekt na odniesienie do id i aktualizacji, jeżeli istnieje lub pchania jeśli nie istnieje.

var parentArray1 = [{ "id": 1, "name": "test", "context": [{ "id": 1.1, "name": "test 1.1" }] }, { "id": 2, "name": "test" }, { "id": 3, "name": "test", "context": [{ "id": 3.1, "name": "test 3.1" }] }, { "id": 4, "name": "test" }], 
 
    changedArray = [{ "id": 1, "name": "test1", "context": [{ "id": 1.1, "name": "Changed test 1.1" }] }, { "id": 5, "name": "test5" }]; 
 

 
function insert(array, data) { 
 
    function iter(array) { 
 
     array.forEach(function (a) { 
 
      if (!('id' in a)) { 
 
       return; 
 
      } 
 
      if (o[a.id] !== a) { 
 
       o[a.id] = a; 
 
      } 
 
      Object.keys(a).forEach(function (k) { 
 
       Array.isArray(a[k]) && iter(a[k]); 
 
      }); 
 
     }); 
 
    } 
 

 
    var o = {}; 
 

 
    iter(array); 
 
    data.forEach(function (a) { 
 
     if (o[a.id]) { 
 
      Object.keys(a).forEach(function (k) { 
 
       o[a.id][k] = a[k]; 
 
      }); 
 
      return; 
 
     } 
 
     array.push(a); 
 
    });    
 
} 
 

 
insert(parentArray1, changedArray); 
 
document.write('<pre>' + JSON.stringify(parentArray1, 0, 4) + '</pre>');

+0

Dzięki za odpowiedź .. ale dlaczego używasz Array.isArray (a.context) && iter (a.context); Ponieważ nie będę znał własności Nazwy obiektów będę przekazywał własność uniqe nanes tj., Id – forgottofly

+1

, która jest zbudowanie obiektu ze wszystkimi odwołującymi się do identyfikatorów w obiekcie, na przykład, jeśli masz 'id = '1.1' ', następnie obiekt' o' ma odniesienie do węzła o tym identyfikatorze, jeśli istnieje. funkcja zasadniczo chodzi po drzewie. –

+0

Ale nie będę znać nazwy "kontekst" i wewnątrz kontekstu znowu może być inny obiekt o innej nazwie – forgottofly

1

Lekka modyfikacja kodu, aby spełnić warunki. Spróbuj!

function compareArray(originalArray, destinationArray, propertyArray) { 
      var newItem = new Array(), processedItem = new Array(); 
      for (var i = 0; i < originalArray.length; i++) { 
       var sourceElement = originalArray[i]; 

       for (var j = 0; j < destinationArray.length; j++) { 
        var destinationElement = destinationArray[j]; 
        var isUpdated = false; 

        if (sourceElement.constructor === Array) { 
         compareArray(sourceElement, destinationElement, propertyArray); 
        } else { 
         /* loop the property name to validate */ 

         propertyArray.map(function(property) { 
          if (sourceElement[property]) { 
           if (sourceElement[property] === destinationElement[property]) { 
            originalArray[i] = _.clone(destinationElement); 
            isUpdated = true; 
            return; 
           } else { 
            var isAvailable = _.find(newItem, function(item) { 
             return item[property] === destinationElement[property]; 
            }); 
            if (!isAvailable) { 
             var isAlreadyProcessed = _.find(processedItem, function(item) { 
              return item[property] === destinationElement[property]; 
             }); 
             if(!isAlreadyProcessed){ 
              newItem.push(destinationElement); 
             } 
            } 
           } 
          } 
         }); 
        } 
        if (isUpdated === true) { 
         break; 
        } 
       } 
       processedItem.push(sourceElement); 
      } 
       newItem.map(function(item) { 
        originalArray.push(item); 
       }); 

       return originalArray; 
     } 
Powiązane problemy