2016-03-21 13 views
5

下面是我的兩個數組。我想比較它們,結果數組應包含更新的值.Id的常見.. 數組跨越n層,即,沒有固定的水平..比較兩個數組,並通過保留現有對象使用javascript來更新新值使用javascript

第一陣列即,更新用前陣..

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

,我執行被

1.Adding一個新的操作Item 2.Upda婷現有項目

由於這兩個操作所改變的值,我會在不同的陣列會越來越.. 即的結果,

var changedArray= 

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

現在我已經寫了通過循環的通用功能parentArray1並使用所述唯一propertiesI需要或者在changedArray在任何級別

所得陣列應增加一個新項目時,如果該項目是有或更新現有的項目..

[ 
    { 
     "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" 
    } 
] 

通用功能:

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

您共享的代碼具有額外的功能,以防數組中的項目也是數組。你想保存嗎?另外,讓我們假設你有一些像'{a:{b:'value'}}'作爲array2中的項目。如果要更新原始對象中的a的值,是否要用'='更新它,這意味着您只更新對象的引用,或者是否要克隆'{b:'value' }對象,並有另一個具有相同值的實例? –

+0

在我的情況下,數組嵌套有不同的屬性,如果值是對象,那麼我們應該克隆。數組中唯一的標識符是屬性名稱,即。,ID的 – forgottofly

+0

我認爲你的問題太複雜了,難道你不能確定你遇到的確切問題?什麼不像你認爲的那樣工作? – froginvasion

回答

0

這是我想出了:

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

} 

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

注意使用它,它不會與包含函數對象。另外,如果數組很大,也許更好的解決方案是按鍵對兩個數組進行排序,然後始終從最後找到的對象開始查找。這就是我現在得到的。

用Nina的一些概念和代碼的一些清除更新它。

據我瞭解,你只想添加屬性。因此,擴展({a:{b:2}},{a:{c:3}})將導致{a:{b:2,c:3}}。如果這不是你想要的,請告訴我。

我還添加了刪除ID的功能。如果數組中的任何對象包含[{id: 4},{id: 5}]形式的removedIds數組,則具有這些ID的項目將從原始數組中移除。

+0

請檢查此plunker https://plnkr.co/edit/KEZs1dWlJRWpMslC2pZL?p=preview我已添加帶有activityId 23的新活動其顯示,但帶有id的現有活動如何22 – forgottofly

+0

這裏有些子對象沒有ID。 sameKeys函數發現沒有id密鑰的兩個對象具有相同的密鑰,算法只採用第一個。我不知道你是如何工作的:使用任何以id結尾的密鑰?因此,而不是使用數組中的所有鍵,使用其中任何一個? 我已經更新了代碼,要求所有比較對象的鍵,並且如果在同一個鍵組合中找到多個項目,則會拋出異常。 –

+0

我有另一個要求,就好像我刪除了changedArray中的對象,即:{ 「id」:1.1, 「name」:「Changed test 1.1」 } 我想在運行compareArray函數後刪除parentArray1中的對象。我該怎麼做。請指導 – forgottofly

1

我建議如果存在使用臨時對象的參考id和更新,或者如果不存在推。

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

感謝您的答覆..但爲什麼你使用Array.isArray(a.context)&& iter(a.context);因爲我不會知道屬性對象名稱,我將傳遞uniqe屬性nanes,即id – forgottofly

+1

,即構建一個對象,並引用所有對象中的id,例如,如果您有'id ='1.1' ',那麼對象'o'具有對具有該id的節點的引用,如果存在的話。功能基本上是在樹上行走。 –

+0

但是我不會知道名稱「上下文」,並且在上下文中,如果其他屬性內部有數組,則可能會有另一個名稱不同的對象 – forgottofly

1

代碼稍作修改,以滿足您的條件。嘗試一下!

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; 
     } 
相關問題