如何检查对象数组是否是其他数组的子集

how to check whether object array is subset of other array

我需要检查 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

Ramda 解决方案

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 来实现它。我做错了什么?

尽管 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 takes a property name and returns a predicate function which reports whether the two supplied parameters have the same value for that property. differenceWith 采用报告两个值是否相等的谓词函数和 returns 接受两个列表的二元函数,并返回第二个参数不在第一个参数中的所有元素根据那个谓词。

我们使用 compose, with an obvious isEmpty 组合这些,我们得到一个相当紧凑的 isSubset

请注意,这比

等 vanilla JS 版本效率低
const isSubset = (xs, ys) => 
  xs .every (x => ys .findIndex (y => x .id == y .id) > -1)

因为我们遍历了第一个集合的所有元素,即使我们发现一个早期的元素不包括在内。

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