比较两个嵌套数组和对象以查找差异

我有两个带有多级嵌套的JSON数据。我想通过以下条件进行比较: 1)如果第一个对象中的名称等于第二个对象中的名称,则比较它们的prop数组;否则,如果两个对象中没有相等的名称,则返回空数组; 2)将对象比较成两个prop数组并找出差异; 3)返回与第一个数组和第二个数组不同的新对象。

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

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

结果应如下所示:

const result = [{
  name: 'B [1]',propOne: [{
    A: { B: 2 },O: 'Missing' }
  }],propTwo: [{
    A: { B: 8 },D: 'Missing',O: 9 }
  }],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;
  },[])
}

我将非常感谢您的帮助和建议。

supportjj 回答:比较两个嵌套数组和对象以查找差异

所有困难都在于指定比较功能的预期行为:

对于两个对象(我称为值)ab{A:1,B:2}{A:1,B:3,C:4} cmp(a,b)的输出应为:

  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,C: { C: 78,D: 4,T: 7,} }],},{
  name: 'B [2]',// name equals,then skiping it
  prop: [{ 
    A: { A: 1,D: { C: 3,Y: 13 } }],{
  name: 'B [3]',then comparing it
  prop: [{ 
    E: { A: 1,R: { A: 1,T: { C: 3,{
  name: 'B [4]',// name and prop equals,then skiping it 
  prop: [{ 
    A: { A: 1,S: { A: 1,}]

const p2 = [{
  name: 'B [1]',then comparing it 
  prop: [{ 
    A: { A: 1,B: 8 },C: { C: 3,O: 9 } }],{
  name: 'B [6]',// name not equals,D: 4 } }],B: 2,U: 150 },}];

console.log('result',JSON.stringify(diff(p1,p2),null,2))

,

有点晚了,我现在没有时间进行大量测试,因此这可能会出现一些意外情况的错误(我希望不是)。发表评论的时间太长了,放弃评论会很浪费。

下面的代码包含两种方式:一种是建设性的,以空对象开始,构建,另一种是围绕性的,以完整对象开始,然后删除。

请注意,在您的数据结构中,有多个“一个元素数组”。如果这些元素可以包含一个以上的元素(对我而言它们并没有多大意义,它已经是数组中数组中的对象,为其他道具提供了足够的空间),则需要额外增加一两个map步骤,不过没什么大问题。

const p1 = [{
  name: 'B [1]',then comparing it
  prop: [{
    A: { A: 1,}
  }],then skiping it
  prop: [{
    A: { A: 1,Y: 13 }
  }],then comparing it
  prop: [{
    E: { A: 1,then skiping it 
  prop: [{
    A: { A: 1,}];

const p2 = [{
  name: 'B [1]',then comparing it 
  prop: [{
    A: { A: 1,O: 9 }
  }],D: 4 }
  }],}];

const result = [{
  name: 'B [1]',propOne: [{
    A: { B: 2 },O: 'Missing' }
  }],propTwo: [{
    A: { B: 8 },D: 'Missing',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,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>

本文链接:https://www.f2er.com/3142083.html

大家都在问