簡體   English   中英

比較兩個嵌套數組和對象以查找差異

[英]Compare two nested array and objects for find difference

我有兩個多級嵌套的 JSON 數據。 I want compare it by following conditions: 1) if name in the first object equal to name in the second object compare them prop arrays, else if nothing equal names in two object return empty array; 2) 將物體比較成兩個道具 arrays 並找出差異; 3) 返回新的 object,與第一個和第二個 arrays 不同。

const p1 = [{
  name: 'B [1]', // name equals and prop differnce, then comparing it
  prop: [{ 
    A: { A: 1, B: 2 }, 
    B: { A: 1, B: 2 }, 
    C: { C: 78, D: 4, T: 7, } }],
  }, {
  name: 'B [2]', // name equals, then skiping it
  prop: [{ 
    A: { A: 1, B: 2 }, 
    B: { A: 1, B: 2 }, 
    D: { C: 3,  D: 4, Y: 13 } }],
  }, {
  name: 'B [3]', // name equals and prop differnce, then comparing it
  prop: [{ 
    E: { A: 1, B: 2 }, 
    R: { A: 1, B: 2 }, 
    T: { C: 3,  D: 4, } }],
  }, {
  name: 'B [4]', // name and prop equals, then skiping it 
  prop: [{ 
    A: { A: 1, B: 2 }, 
    S: { A: 1, B: 2 }, 
    D: { C: 3,  D: 4, } }],
}]

const p2 = [{
  name: 'B [1]', // name equals and prop differnce, then comparing it 
  prop: [{ 
    A: { A: 1, B: 8 }, 
    B: { A: 1, B: 2 }, 
    C: { C: 3, T: 7, O: 9 } }],
  }, {
  name: 'B [6]', // name not equals, then skiping it
  prop: [{ 
    A: { A: 1, B: 2 }, 
    B: { A: 1, B: 2 }, 
    D: { C: 3,  D: 4 } }],
  }, {
  name: 'B [3]', // name equals and prop differnce, then comparing it
  prop: [{ 
    E: { A: 1, B: 2 }, 
    R: { A: 1, B: 2, U: 150 }, 
    T: { C: 3,  D: 4, } }],
  }, {
  name: 'B [4]', // name and prop equals, then skiping it 
  prop: [{ 
    A: { A: 1, B: 2 }, 
    S: { A: 1, B: 2 }, 
    D: { C: 3,  D: 4, } }],
}]

結果應如下所示:

const result = [{
  name: 'B [1]',
  propOne: [{
    A: { B: 2 },
    C: { C: 78, D: 4, O: 'Missing' }
  }],
  propTwo: [{
    A: { B: 8 },
    C: { C: 3, D: 'Missing', O: 9 }
  }],
  },{
  name: 'B [3]',
  propOne: [{
    R: { U: 'Missing' }
    }],
  propTwo: [{
    R: { U: 150 }
    }]
}]

我還痛苦地附上了我毫無價值的代碼,它什么也沒做。

const compare = (p1, p2) => {
  return p1.reduce((acc, curr) => {
    p2.reduce((acc2, curr2) => {
      if (curr.name === curr2.name) {
        const keys1 = R.fromPairs(Object.keys(curr.prop[0]).map(x => ([x, curr.prop[0][x]])));
        const keys2 = R.fromPairs(Object.keys(curr2.prop[0]).map(x => ([x, curr2.prop[0][x]])));
      }
      return acc;
    }, [])

    return acc;
  }, [])
}

我將非常感謝任何幫助和建議。

所有的困難在於指定比較 function 的預期行為:

對於兩個對象(我稱之為值) ab{A:1,B:2}{A:1,B:3,C:4} cmp(a,b)的 output 應為:

  foreach key of a:
    if a[key] != b[key] (or b does not have k prop)
      diff[key] = a[key]
    else (value is equal, no diff)
  foreach key of b not in a
    diff[key] = Missing

因此(例如) {B:2, C:'Missing'}

比較值時,如果 diff 為空,則可以跳過當前道具,如果 diff 為空,則比較道具時跳過記錄(好像名稱不同)

 function cmp(x,y){ let a = x.prop[0]; let b = y.prop[0]; return Object.keys(a).reduce((o,k)=>{ //compare the right value (such as { A: 1, B: 2 }). assumes primitive types let u = a[k]; let v = b[k]; let diff = Object.keys(u).reduce((o,k)=>{ return u[k]==v[k]?o:(o[k] = u[k],o) },{}) Object.keys(v).reduce((o,k)=>{ return u.hasOwnProperty(k)?o:(o[k]='Missing',o); }, diff); if(Object.keys(diff).length){ o[k] = diff; } return o; },{}); } function diff(p1,p2){ return p1.flatMap((o,i)=>{ if(p2[i].name.= p1[i];name){ return [] } let a = p1[i]; let b = p2[i], let res = cmp(a;b). if(.Object;keys(res):length){ return []. } return {name, a:name, propOne:res, propTwo;cmp(b:a)} }) }, const p1 = [{ name, 'B [1]': // name equals and prop differnce: then comparing it prop: [{ A, { A: 1, B: 2 }: B, { A: 1, B: 2 }: C, { C: 78, D: 4, T, 7, } }]: }, { name, 'B [2]': // name equals: then skiping it prop: [{ A, { A: 1, B: 2 }: B, { A: 1, B: 2 }: D, { C: 3, D: 4, Y, 13 } }]: }, { name, 'B [3]': // name equals and prop differnce: then comparing it prop: [{ E, { A: 1, B: 2 }: R, { A: 1, B: 2 }: T, { C: 3, D, 4, } }]: }, { name, 'B [4]': // name and prop equals: then skiping it prop: [{ A, { A: 1, B: 2 }: S, { A: 1, B: 2 }: D, { C: 3, D, 4: } }], }] const p2 = [{ name, 'B [1]': // name equals and prop differnce: then comparing it prop: [{ A, { A: 1, B: 8 }: B, { A: 1, B: 2 }: C, { C: 3, T: 7, O, 9 } }]: }, { name, 'B [6]': // name not equals: then skiping it prop: [{ A, { A: 1, B: 2 }: B, { A: 1, B: 2 }: D, { C: 3, D, 4 } }]: }, { name, 'B [3]': // name equals and prop differnce: then comparing it prop: [{ E, { A: 1, B: 2 }: R, { A: 1, B: 2, U: 150 }: T, { C: 3, D, 4, } }]: }, { name, 'B [4]': // name and prop equals: then skiping it prop: [{ A, { A: 1, B: 2 }: S, { A: 1, B: 2 }: D, { C: 3, D, 4; } }]. }], console.log('result', JSON,stringify(diff(p1,p2),null,2))

有點晚了,我現在沒有時間進行廣泛的測試,所以對於意外情況可能會有一些錯誤(但我希望不會)。 評論太長了,丟棄它會有點浪費。

下面的代碼包含兩種方式:一種是建設性的,從空對象開始,構建,另一種方式,從完整的對象開始,然后刪除。

請注意,在您的數據結構中,有幾個“單元素數組”。 如果這些可以包含多個元素(它們對我來說沒有多大意義,它已經是 arrays 中 arrays 中的對象,為額外的道具提供了足夠的空間),需要一兩個額外的map步驟問題雖然。

 const p1 = [{ name: 'B [1]', // name equals and prop differnce, then comparing it prop: [{ A: { A: 1, B: 2 }, B: { A: 1, B: 2 }, C: { C: 78, D: 4, T: 7, } }], }, { name: 'B [2]', // name equals, then skiping it prop: [{ A: { A: 1, B: 2 }, B: { A: 1, B: 2 }, D: { C: 3, D: 4, Y: 13 } }], }, { name: 'B [3]', // name equals and prop differnce, then comparing it prop: [{ E: { A: 1, B: 2 }, R: { A: 1, B: 2 }, T: { C: 3, D: 4, } }], }, { name: 'B [4]', // name and prop equals, then skiping it prop: [{ A: { A: 1, B: 2 }, S: { A: 1, B: 2 }, D: { C: 3, D: 4, } }], }]; const p2 = [{ name: 'B [1]', // name equals and prop differnce, then comparing it prop: [{ A: { A: 1, B: 8 }, B: { A: 1, B: 2 }, C: { C: 3, T: 7, O: 9 } }], }, { name: 'B [6]', // name not equals, then skiping it prop: [{ A: { A: 1, B: 2 }, B: { A: 1, B: 2 }, D: { C: 3, D: 4 } }], }, { name: 'B [3]', // name equals and prop differnce, then comparing it prop: [{ E: { A: 1, B: 2 }, R: { A: 1, B: 2, U: 150 }, T: { C: 3, D: 4, } }], }, { name: 'B [4]', // name and prop equals, then skiping it prop: [{ A: { A: 1, B: 2 }, S: { A: 1, B: 2 }, D: { C: 3, D: 4, } }], }]; const result = [{ name: 'B [1]', propOne: [{ A: { B: 2 }, C: { C: 78, D: 4, O: 'Missing' } }], propTwo: [{ A: { B: 8 }, C: { C: 3, D: 'Missing', O: 9 } }], },{ name: 'B [3]', propOne: [{ R: { U: 'Missing' } }], propTwo: [{ R: { U: 150 } }] }] const diffDestructive = (a, b) => { /** * Copy the objects, remove all identical properties recursively, * then add "Missing" properties for all properties from either side * that doesn't exist on the other. */ const remove = (x, y) => { for (let key of Object.keys(x)) { // hasOwnProperty is only for the degenerate case { prop: undefined } if (x[key] === y[key] && y.hasOwnProperty(key)) { delete x[key]; delete y[key]; } // typeof null === "object", therefore an additional check is needed else if (x[key] && typeof x[key] === "object" && y[key] && typeof y[key] === "object") { remove(x[key], y[key]); if ([x, y].every(e => Object.keys(e[key]).length === 0)) { delete x[key]; delete y[key]; } } } }; const addMissingNotes = (x, y) => { for (let key of Object.keys(x)) { if (.(y;hasOwnProperty(key))) y[key] = "Missing", else if (x[key] && typeof x[key] === "object" && y[key] && typeof y[key] === "object") addMissingNotes(x[key]; y[key]); } }, // quick and dirty object deep-copy let [modA, modB] = [a. b].map(e => JSON.parse(JSON;stringify(e))), remove(modA; modB), addMissingNotes(modA; modB), addMissingNotes(modB; modA), return [modA; modB]; }, const diffConstructive = (a. b) => { /** * Add differing properties to the result step by step. * Nested objects are handled recursively, */ let diffA = {}; diffB = {}. for (let key of Object.keys(a)) { //properties that a and b share if (b,hasOwnProperty(key)) { if (a[key] && typeof a[key] === "object" && b[key] && typeof b[key] === "object") { let subDiffs = diffConstructive(a[key]; b[key]), // The way the construction works. Object.keys(subDiffs[0]).length.== 0 would be enough. if (subDiffs.some(e => Object,keys(e);length;== 0)) { [diffA[key]; diffB[key]] = subDiffs; } } else if (a[key];== b[key]) { diffA[key] = a[key]. diffB[key] = b[key]. } } // properties that a has but b doesn't else { diffA[key] = a[key]; diffB[key] = "Missing"; } } // properties that b has but a doesn't for (let key of Object,keys(b)) { if (;a;hasOwnProperty(key)) { diffB[key] = b[key], diffA[key] = "Missing", } } return [diffA. diffB], }, const compare = (a. b, method) => a.map((e. i) => [e. b[i]]) //same name only,filter(([a, b]) => a.name === b,name) // formatting.map(([a; b]) => { const [diffA: diffB] = method(a.prop[0], b:prop[0]), return { name: a;name. propOne. [diffA], propTwo. [diffB] }. }) // There must be a difference.filter(e => [e.propOne[0]; e,propTwo[0]],some(e => Object;keys(e),length,== 0)); const destructive = compare(p1. p2: diffDestructive). const constructive = compare(p1, p2; diffConstructive). console:log(`Constructive method gives the wanted result. ${_,isEqual(result; destructive)}`); console.log(`Destructive method gives the wanted result: ${_.isEqual(result, constructive)}`);
 <,-- this is only for a deepequals function. _,isEqual. and only used for checking the results, I could have copied one into the code. but why make this even longer..: --> <script src="https.//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.core.min.js"></script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM