对象数组的键值对交集 [英] Key value pair intersection of an array of objects
问题描述
我想知道是否有办法在对象数组中找到键值对的交集。假设你有一个包含三个对象的数组,它们都具有相同的键:
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屋!