首页 > 解决方案 > 如何检查对象数组是否是其他数组的子集

问题描述

我需要检查 arr1 是否是 arr2 的子集,前提是两个元素的 id 相等。

arr1 = [{id:1, value:8}, {id: 2, value: 9};
arr2 = [{id: 1, category: 'a1'}, {id: 2, category: 'a2'}, {id: 3, category: 'a3'}]

我可以用普通的 JS 做到这一点。但我无法对 Ramda 做同样的事情。我的 ramda 解决方案导致错误

core.js:6456 ERROR TypeError: g.call is not a function

拉姆达解决方案

export const isSubset = (arr: Identifier[]) => all(
  compose(
    isNotNullOrEmpty,
    filter(propEq('id', identity), arr),
    prop('id')
  )
);
export const isNilOrEmpty = either(isNil, isEmpty);

export const isNotNullOrEmpty = compose(not, isNilOrEmpty);

isSubsetOfInputIdentifiers(arr2)(arr1))

纯Js解决方案

arr1.every(
    (identifier) =>
      arr2?.findIndex(
        (identifier1) =>
          identifier1.id === identifier.id
      ) >= 0
  )

我只需要使用 ramda 来实现它。我究竟做错了什么?

标签: javascriptramda.js

解决方案


尽管 Ramda 不提供任何isSubset功能,但有必要的工具可以自己编写一个简单的版本:

const isSubset = compose (isEmpty, differenceWith (eqProps ('id')))


const arr1 = [{id:1, value:8}, {id: 2, value: 9}];
const arr2 = [{id: 1, category: 'a1'}, {id: 2, category: 'a2'}, {id: 3, category: 'a3'}]
const arr3 = [{id:1, value:8}, {id: 5, value: 11}];

console .log (isSubset (arr1, arr2))
console .log (isSubset (arr3, arr2))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {compose, isEmpty, differenceWith, eqProps} = R           </script>

在这里,eqProps接受一个属性名称并返回一个谓词函数,该函数报告两个提供的参数是否具有该属性的相同值。 differenceWith接受一个谓词函数,该函数报告两个值是否相等并返回一个接受两个列表的二元函数,并根据该谓词返回第二个参数中不在第一个参数中的所有元素。

我们将这些结合起来,使用compose, 与一个明显isEmpty的 ,我们得到一个相当紧凑的isSubset

请注意,这比普通 JS 版本效率低,例如

const isSubset = (xs, ys) => 
  xs .every (x => ys .findIndex (y => x .id == y .id) > -1)

因为我们迭代了第一组的所有元素,即使我们找到了一个不包括在内的早期元素。

如果您有兴趣,我们绝对可以使用一些相同的工具编写最后一个 Ramda 版本。isSubset但我只会在上面证明一个真正的性能问题时才会打扰。


推荐阅读