对象数组的键值对交集 [英] Key value pair intersection of an array of objects

查看:97
本文介绍了对象数组的键值对交集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有办法在对象数组中找到键值对的交集。假设你有一个包含三个对象的数组,它们都具有相同的键:

  arrayOfObj = [
{
a:1,
b:stringB
c:{c1:1,
c2:stringC2
}
},
{
a:1,
b:stringBdiff
c:{c1:1,
c2:stringC2
}
},
{
a:1,
b:stringB
c:{c1:1,
c2:stringC2
}
}
]

我想找到三个对象的公共键值对:

  output = [
{a:1},
{c:{c1:1,
c2:stringC2
}
}
]

这是我到目前为止所做的,它适用但不适用于嵌套对象。我想知道是否有一种更优雅的方式可以做到这一点,也可以在嵌套对象上工作。



  let properties;设commonFound = false; let notCommonFound = false; const commonValues = [];让价值; const initialArray = [{a:2,b:stringB,c:{c1:1,c2:stringC2}},{a:1,b :stringB,c:{c1:2,c2:stringC2}},{a:1,b:stringB,c:{c1: 2,c2:stringC2}}]; const commonStorage = []; const reference = initialArray [0]; properties = Object.keys(reference); properties.forEach((property)=> {for(let i = 0; i< initialArray.length; i ++){commonFound = false; notCommonFound = false; for(let j = 0; j< i; j ++) {if(initialArray [i] [property] === initialArray [j] [property]){commonFound = true; value = initialArray [i] [property];} else {notCommonFound = true; value = [];}} } if(commonFound&&!notCommonFound){commonStorage.push({[property]:value});}}); console.log(commonStorage);  

解决方案

在我们实施 union 之前,我们先看看我们的预期行为 -

  console.log 
(union
({a:1,b:2,d:4}
,{a:1,c:3,d :5}

// {a:1}

,union
([1,2,3,4,6,7]
,[1,2,3,5,6]

// [1,2,3,< 1空项>,6]

,工会
([{a:1},{a:2},{a:4,b:5},]
,[{a:1},{a:3},{a: 4,b:6},]

// [{a:1},< 1空项>,{a:4}]

,union
({a:{b:{c:{d:[1,2]}}}}
,{a:{b:{c:{d:[1,2,3]} }

// {a:{b:{c:{d:[1,2]}}}}

像破坏这样的问题变得更容易把它们分成更小的部分。要实现 union ,我们将计划 merge 两次调用 union1 ,每个贡献计算结果的 -

  const union =(left = {} ,right = {})=> 
合并
(union1(左,右)
,union1(右,左)

实现 union1 仍然相对复杂,因为需要支持对象数组 - 序列 map filter reduce 有助于维持流程该计划

  const union1 =(left = {},right = {})=> 
Object.entries(左)
.map
(([k,v])=>
//两个值都是对象
isObject(v)& ;& isObject(右[k])
?[k,union(v,right [k])]
//两个值都是等于
:v ===对[k]
?[k,v]
//否则
:[k,{}]

.filter
(([k ,v])=>
isObject(v)
?Object.keys(v)。length> 0
:true

.reduce
(分配
,isArray(左)&& isArray(右)?[]:{}

最后,我们实现 merge ,就像我们在其他Q& A -

  const merge =(left = {},right = { })=> 
Object.entries(右)
.map
(([k,v])=>
isObject(v)&& isObject(left [k])
?[k,merge(left [k],v)]
:[k,v]

.reduce(assign,left)

最终的依赖关系 -

  const isObject = x => 
Object(x)=== x

const isArray =
Array.isArray

const assign =(o,[k,v]) =>
(o [k] = v,o)

验证完整的程序是否适用于您的下面的浏览器 -



  const isObject = x => Object(x)=== xconst isArray = Array.isArrayconst assign =(o,[k,v])=> (o [k] = v,o)const merge =(left = {},right = {})=> Object.entries(右).map(([k,v])=> isObject(v)&& isObject(left [k])?[k,merge(left [k],v)]:[ k,v])。reduce(assign,left)const union =(left = {},right = {})=> merge(union1(left,right),union1(right,left))const union1 =(left = {},right = {})=> Object.entries(左).map(([k,v])=> isObject(v)&& isObject(right [k])?[k,union(v,right [k])]:v === right [k]?[k,v]:[k,{}])。filter(([k,v])=> isObject(v)?Object.keys(v).length> 0 :true).reduce(assign,isArray(left)&& isArray(right)?[]:{})console.log(union({a:1,b:2,d:4},{a: 1,c:3,d:5})// {a:1},union([1,2,3,4,6,7],[1,2,3,5,6])// [ 1,2,3,< 1空项>,6],union([{a:1},{a:2},{a:4,b:5},],[{a:1}, {a:3},{a:4,b:6},])// [{a:1},< 1空项>,{a:4}],union({a:{b:{ c:{d:[1,2]}}}},{a:{b:{c:{d:[1,2,3}}}}})// {a:{b:{c: {d:[1,2]}}}}) 






unionAll



高于 union 只接受两个输入,在你的问题中,你想要计算2+对象的并集。我们按如下方式实施 unionAll -

  const无= 
符号()

const unionAll =(x =无,... xs)=>
x ===无
? {}
:xs .reduce(union,x)

console.log
(unionAll
({a:1,b:2,c:{d :3,e:4}}
,{a:1,b:9,c:{d:3,e:4}}
,{a:1,b:2,c: {d:3,e:5}}

// {a:1,c:{d:3}}

,unionAll
({ a:1}
,{b:2}
,{c:3}

// {}

,unionAll
()
// {}

验证结果浏览器 -



  const isObject = x => Object(x)=== xconst isArray = Array.isArrayconst assign =(o,[k,v])=> (o [k] = v,o)const merge =(left = {},right = {})=> Object.entries(右).map(([k,v])=> isObject(v)&& isObject(left [k])?[k,merge(left [k],v)]:[ k,v])。reduce(assign,left)const union =(left = {},right = {})=> merge(union1(left,right),union1(right,left))const union1 =(left = {},right = {})=> Object.entries(左).map(([k,v])=> isObject(v)&& isObject(right [k])?[k,union(v,right [k])]:v === right [k]?[k,v]:[k,{}])。filter(([k,v])=> isObject(v)?Object.keys(v).length> 0 :true).reduce(assign,isArray(left)&& isArray(right)?[]:{})const None = Symbol()const unionAll =(x = None,... xs)=> x ===没有? {}:xs .reduce(union,x)console.log(unionAll({a:1,b:2,c:{d:3,e:4}},{a:1,b:9,c: {d:3,e:4}},{a:1,b:2,c:{d:3,e:5}})// {a:1,c:{d:3}},unionAll ({a:1},{b:2},{c:3})// {},unionAll()// {}) 






备注



你会想要考虑一些事情 -

  union 
({a:someFunc,b: x => x * 2,c:/ foo /,d:1}
,{a:someFunc,b:x => x * 3,c:/ foo /,d:1}

// {d:1}(实际)
// {a:someFunc,c:/ foo /,d:1}(预期)

我们在 union1 等于的内容> -

  const union1 =(left = {},right = {})=> 
Object.entries(左)
.map
(([k,v])=>
isObject(v)&& isObject(right [k])
?[k,union(v,right [k])]
:v === right [k] //< - 相等?
?[k,v]
:[k,{}]

.filter
(...

如果我们想支持诸如检查函数,RegExps或其他对象的相等性,我们将在此处进行必要的修改






recursive diff



这个相关的Q& A 我们计算递归 diff 两个对象


I would like to know if there is a way to find the intersection of a key value pair in an array of objects. Let's say you have an array of three objects which all have the same keys like this :

    arrayOfObj = [
    {
        "a": 1,
        "b": "stringB"
        "c": {"c1":1,
            "c2": "stringC2"
            }
    },
    {
        "a": 1,
        "b": "stringBdiff"
        "c": {"c1":1,
            "c2": "stringC2"
            }
    },
    {
        "a": 1,
        "b": "stringB"
        "c": {"c1":1,
            "c2": "stringC2"
            }
    }
  ]

I would like to find the common key value pairs of the three objects:

output= [
 {"a":1}, 
 {"c": {"c1":1, 
        "c2":"stringC2"
       }
 }
]

This is what I have done so far, it works but not on nested objects. I would like to know if there is a more elegant way to do it and one that could work on nested object as well.

    let properties;
    let commonFound = false;
    let notCommonFound = false;
   const commonValues = [];
   let value;
   const initialArray = [{
   "a": 2,
   "b": "stringB",
   "c": {
     "c1": 1,
     "c2": "stringC2"
   }
  },
  {
   "a": 1,
   "b": "stringB",
   "c": {
     "c1": 2,
     "c2": "stringC2"
   }
  },
  {
   "a": 1,
   "b": "stringB",
   "c": {
     "c1": 2,
     "c2": "stringC2"
   }
  }
  
  ];
   
   const commonStorage = [];
   const  reference = initialArray[0];
   properties = Object.keys(reference);
   properties.forEach((property) => {
       for (let i = 0; i < initialArray.length; i++) {
        commonFound = false;
        notCommonFound = false;
          for (let j = 0; j <i ; j++) {        
              if (initialArray[i][property] === initialArray[j][property]) {
                commonFound = true;
                value = initialArray[i][property];
                }
              else {
               notCommonFound = true;
               value = [];
               }         
          }
        }
       if (commonFound && !notCommonFound) {
          commonStorage.push({[property] : value});
       }
   });
     
  console.log(commonStorage);

解决方案

Before we implement union we'll first look at how we expect it to behave –

console.log
  ( union
      ( { a: 1, b: 2, d: 4 }
      , { a: 1, c: 3, d: 5 }
      )
      // { a: 1 }

  , union
      ( [ 1, 2, 3, 4, 6, 7 ]
      , [ 1, 2, 3, 5, 6 ]
      )
      // [ 1, 2, 3, <1 empty item>, 6 ]

  , union
      ( [ { a: 1 }, { a: 2 }, { a: 4, b: 5 }, ]
      , [ { a: 1 }, { a: 3 }, { a: 4, b: 6 }, ]
      )
      // [ { a: 1 }, <1 empty item>, { a: 4 } ]

  , union
      ( { a: { b: { c: { d: [ 1, 2 ]    } } } }
      , { a: { b: { c: { d: [ 1, 2, 3 ] } } } }
      )
      // { a: { b: { c: { d: [ 1, 2 ] } } } }
  )

Challenging problems like this one are made easier by breaking them down into smaller parts. To implement union we will plan to merge two calls to union1, each contributing one side of the computed result –

const union = (left = {}, right = {}) =>
  merge
    ( union1 (left, right)
    , union1 (right, left)
    )

Implementing union1 is remains relatively complex due to the need to support both objects and arrays – the sequence of map, filter, and reduce helps maintain a flow of the program

const union1 = (left = {}, right = {}) =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          // both values are objects
          isObject (v) && isObject (right[k])
            ? [ k, union (v, right[k]) ]
          // both values are "equal"
          : v === right[k]
            ? [ k, v ]
          // otherwise
          : [ k, {} ]
      )
    .filter
      ( ([ k, v ]) =>
          isObject (v)
            ? Object.keys (v) .length > 0
            : true
      )
    .reduce
      ( assign
      , isArray (left) && isArray (right) ? [] : {}
      )

Lastly we implement merge the same way we did in the other Q&A

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (assign, left)

The final dependencies –

const isObject = x =>
  Object (x) === x

const isArray =
  Array.isArray

const assign = (o, [ k, v ]) =>
  (o [k] = v, o)

Verify the complete program works in your browser below –

const isObject = x =>
  Object (x) === x

const isArray =
  Array.isArray

const assign = (o, [ k, v ]) =>
  (o [k] = v, o)

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (assign, left)

const union = (left = {}, right = {}) =>
  merge
    ( union1 (left, right)
    , union1 (right, left)
    )

const union1 = (left = {}, right = {}) =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, union (v, right[k]) ]
            : v === right[k]
              ? [ k, v ]
              : [ k, {} ]
      )
    .filter
      ( ([ k, v ]) =>
          isObject (v)
            ? Object.keys (v) .length > 0
            : true
      )
    .reduce
      ( assign
      , isArray (left) && isArray (right) ? [] : {}
      )

console.log
  ( union
      ( { a: 1, b: 2, d: 4 }
      , { a: 1, c: 3, d: 5 }
      )
      // { a: 1 }

  , union
      ( [ 1, 2, 3, 4, 6, 7 ]
      , [ 1, 2, 3, 5, 6 ]
      )
      // [ 1, 2, 3, <1 empty item>, 6 ]

  , union
      ( [ { a: 1 }, { a: 2 }, { a: 4, b: 5 }, ]
      , [ { a: 1 }, { a: 3 }, { a: 4, b: 6 }, ]
      )
      // [ { a: 1 }, <1 empty item>, { a: 4 } ]

  , union
      ( { a: { b: { c: { d: [ 1, 2 ]    } } } }
      , { a: { b: { c: { d: [ 1, 2, 3 ] } } } }
      )
      // { a: { b: { c: { d: [ 1, 2 ] } } } }
  )


unionAll

Above union only accepts two inputs and in your question you want to compute the union of 2+ objects. We implement unionAll as follows -

const None =
  Symbol ()

const unionAll = (x = None, ...xs) =>
  x === None
    ? {}
    : xs .reduce (union, x)

console.log
  ( unionAll
      ( { a: 1, b: 2, c: { d: 3, e: 4 } }
      , { a: 1, b: 9, c: { d: 3, e: 4 } }
      , { a: 1, b: 2, c: { d: 3, e: 5 } }
      )
      // { a: 1, c: { d: 3 } }

  , unionAll
      ( { a: 1 }
      , { b: 2 }
      , { c: 3 }
      )
      // {}

  , unionAll
      ()
      // {}
  )

Verify the results in your browser –

const isObject = x =>
  Object (x) === x

const isArray =
  Array.isArray

const assign = (o, [ k, v ]) =>
  (o [k] = v, o)

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (assign, left)

const union = (left = {}, right = {}) =>
  merge
    ( union1 (left, right)
    , union1 (right, left)
    )

const union1 = (left = {}, right = {}) =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, union (v, right[k]) ]
            : v === right[k]
              ? [ k, v ]
              : [ k, {} ]
      )
    .filter
      ( ([ k, v ]) =>
          isObject (v)
            ? Object.keys (v) .length > 0
            : true
      )
    .reduce
      ( assign
      , isArray (left) && isArray (right) ? [] : {}
      )

const None =
  Symbol ()

const unionAll = (x = None, ...xs) =>
  x === None
    ? {}
    : xs .reduce (union, x)
    
console.log
  ( unionAll
      ( { a: 1, b: 2, c: { d: 3, e: 4 } }
      , { a: 1, b: 9, c: { d: 3, e: 4 } }
      , { a: 1, b: 2, c: { d: 3, e: 5 } }
      )
      // { a: 1, c: { d: 3 } }

  , unionAll
      ( { a: 1 }
      , { b: 2 }
      , { c: 3 }
      )
      // {}
      
  , unionAll
      ()
      // {}
  )


remarks

You'll want to consider some things like –

union
  ( { a: someFunc, b: x => x * 2, c: /foo/, d: 1 }
  , { a: someFunc, b: x => x * 3, c: /foo/, d: 1 }
  )
  // { d: 1 }                          (actual)
  // { a: someFunc, c: /foo/, d: 1 }   (expected)

We're testing for what's considered equal here in union1

const union1 = (left = {}, right = {}) =>
  Object.entries (left)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (right[k])
            ? [ k, union (v, right[k]) ]
            : v === right[k] // <-- equality?
              ? [ k, v ]
              : [ k, {} ]
      )
    .filter
      ( ...

If we want to support things like checking for equality of Functions, RegExps, or other objects, this is where we would make the necessary modifications


recursive diff

In this related Q&A we compute the recursive diff of two objects

这篇关于对象数组的键值对交集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆