简体   繁体   English

使用动态键查找 2 个对象数组之间的交集

[英]Finding intersection between 2 arrays of objects with dynamic keys

I have 2 arrays of objects with dynamic keys (i never know the name of the key);我有 2 个带有动态键的对象数组(我从不知道键的名称); Example:例子:

hierarchy1: [
  {
    level1: 'Shoes',
  }
]

hierarchy2: [
  {
    level1: 'Shoes',
    level2: 'Sneakers',
  },
]

I need to find intersection between hierarchy1 and hierarchy2.我需要找到hierarchy1和hierarchy2之间的交集。 I can't use lodash _.intersectionBy because i dont know the name of the key i will get in hierarchy1 .我不能使用 lodash _.intersectionBy 因为我不知道我将在hierarchy1中获得的密钥的名称。

I'd expect to get the result like this [{ level1: 'Shoes' }] Any ideas how to solve this issue?我希望得到这样的结果 [{ level1: 'Shoes' }] 任何想法如何解决这个问题?

Thanks a lot!非常感谢!

if you want to compare with every index then you can do something like this如果你想与每个索引进行比较,那么你可以做这样的事情

 const hierarchy1 = [{ level1: 'Shoes', level3: "xyz" }] const hierarchy2 = [{ level1: 'Shoes', level2: 'Sneakers', }, { level3: "xyz" }] function intersection(arr1, arr2) { let final = [] // loop over first array for (let i = 0; i < arr1.length; i++) { let element = arr1[i] let temp = {} // loop over all indexes of second array for (let data of arr2) { // check every key fro data to see if there's any intersection Object.keys(data).forEach(key => { if (data[key] === element[key] && key in element) { temp[key] = element[key] } }) } // if we found any intersection push it in final array if (Object.keys(temp).length) { final.push(temp) } } return final } console.log(intersection(hierarchy1, hierarchy2))

an improvement to first approach is doing some pre-calculations, you can simply club all the values for a particular key and when looping over you can check if there's particular value present for the given key or not对第一种方法的改进是进行一些预先计算,您可以简单地将特定键的所有值组合在一起,并且在循环时您可以检查给定键是否存在特定值

 const hierarchy1 = [{ level1: 'Shoes', level3: "xyz" },{level2: "abc"}] const hierarchy2 = [{ level1: 'Shoes', level2: 'Sneakers', }, { level3: "xyz", level2: "abc" }] function intersection(arr1, arr2) { let final = [] let map = {} for(let data of arr2){ Object.keys(data).forEach(key => { map[key] = map[key] || new Set() map[key].add(data[key]) }) } // loop over first array for (let i = 0; i < arr1.length; i++) { let element = arr1[i] let temp = {} Object.keys(element).forEach(key => { if (key in map && map[key].has(element[key])) { temp[key] = element[key] } }) // if we found any intersection push it in final array if (Object.keys(temp).length) { final.push(temp) } } return final } console.log(intersection(hierarchy1, hierarchy2))

If you just want to compare respective indexes or both array you can do something like this如果您只想比较各自的索引或两个数组,您可以执行以下操作

 const hierarchy1 = [{ level1: 'Shoes', }] const hierarchy2 = [{ level1: 'Shoes', level2: 'Sneakers', },] function intersection(arr1,arr2){ let final = [] for(let i=0; i<arr1.length; i++){ let element = arr1[i] let temp = {} Object.keys(element).forEach(key => { if(key in arr2[i] && arr2[i][key] === element[key]){ temp[key] = element[key] } }) if(Object.keys(temp).length){ final.push(temp) } } return final } console.log(intersection(hierarchy1,hierarchy2))

You can use _.intersectionWith() that accepts multiple arrays, and a comparator function to compare between two items.您可以使用接受多个数组的_.intersectionWith()和一个比较器函数来比较两个项目。 To find matching keys, we can use _.intersection() between the keys of the two objects, and then use Array.some() to find at least one key that have matching values in both objects.要找到匹配的键,我们可以在两个对象的键之间使用_.intersection() ,然后使用Array.some()找到两个对象中至少一个具有匹配值的键。

 const intersectionWithDynamicKeys = (arr1, arr2) => _.intersectionWith( arr1, arr2, (o1, o2) => _.union(_.keys(o1), _.keys(o2)) .some(key => o1[key] === o2[key]) ) // Finds [{ level1: 'Shoes' }] console.log(intersectionWithDynamicKeys( [{ level1: 'Shoes' }], [{ level1: 'Shoes', level2: 'Sneakers' }] )) // Finds [{ level1: 'Shoes' }] but doesn't find { level2: 'Sneakers' console.log(intersectionWithDynamicKeys( [{ level1: 'Shoes' }, { level2: 'Sneakers' }], [{ level1: 'Shoes', level2: 'Sneakers' }] ))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

The main caveat using _.intersectionWith() is that as soon as an item matches it's not used again.使用_.intersectionWith()的主要警告是,一旦项目匹配,它就不会再次使用。 So if for example you have因此,例如,如果您有

const arr1 = [{ level1: 'Shoes' }, { level2: 'Sneakers' }],
const arr2 = [{ level1: 'Shoes', level2: 'Sneakers' }]

only the { level1: 'Shoes' } because { level1: 'Shoes', level2: 'Sneakers' } would not be used to compare with { level2: 'Sneakers' } , since a match was found.只有{ level1: 'Shoes' }因为{ level1: 'Shoes', level2: 'Sneakers' }不会用于与{ level2: 'Sneakers' }进行比较,因为找到了匹配项。

If you want to find all objects with matching keys, you'll need to compare all objects in one array to all objects in the other.如果要查找具有匹配键的所有对象,则需要将一个数组中的所有对象与另一个数组中的所有对象进行比较。 To do so, filter the 1st array.为此,请过滤第一个数组。 Use Array.some() to iterate the 2nd array.使用Array.some()迭代第二个数组。 Get all unique keys (using a Set ), and then try to find at least one key that has the same value in both objects.获取所有唯一键(使用Set ),然后尝试在两个对象中找到至少一个具有相同值的键。

Note : without the match once limit, multiple objects from the 1st array can be matched by a single object in the 2nd.注意:没有匹配一次限制,第一个数组中的多个对象可以与第二个数组中的单个对象匹配。

 const getUniqueKeys = (o1, o2) => [...new Set([...Object.keys(o1), ...Object.keys(o2)])] const intersectionWithDynamicKeys = (arr1, arr2) => arr1.filter(o1 => arr2.some(o2 => getUniqueKeys(o1, o2) .some(key => o1[key] === o2[key]) ) ) // Finds [{ level1: 'Shoes' }, { level2: 'Sneakers' }] console.log(intersectionWithDynamicKeys( [{ level1: 'Shoes' }, { level2: 'Sneakers' }], [{ level1: 'Shoes', level2: 'Sneakers' }] )) // Finds [{ level1: 'Shoes' }, { level2: 'Sneakers' }, { level2: 'Sneakers' }] console.log(intersectionWithDynamicKeys( [{ level1: 'Shoes' }, { level2: 'Sneakers' }, { level2: 'Sneakers' }], [{ level1: 'Shoes', level2: 'Sneakers' }] ))

You can use this to reshape it a tad.您可以使用它来稍微重塑它。

var all = [...hierarchy1, ...hierarchy2].map(c=> Object.entries(c)).flat()
/*
[
  [ 'level1', 'Shoes' ],
  [ 'level1', 'Shoes' ],
  [ 'level2', 'Sneakers' ]
]
*/

Then put it into whatever format you want after that然后把它变成你想要的任何格式

all.reduce((a,[key,value])=>({
     ...a, 
    [key]: a[key]?a[key]+1:1
  }),{})

/*
{ level1: 2, level2: 1 }
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM