使用 Ramda 过滤每个内部 属性 数组

Filter each inner property arrays with Ramda

我有一个这样的对象:

const arrays = {
  one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
  two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
  three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};

如您所见,每个 第一个数字 是相等的:
1 每个第一个 内部数组
每秒2 内部数组
3 每三个 内部数组
等...

我想根据每个数组的第一个数字过滤 和一些比较器编号,例如[3]
如果我们有一个过滤器编号[3](小于或等于3), 想要的结果是:

const arrays = {
  one:   [[1,33,41], [2,0,27], [3,7,9]],
  two:   [[1,77,2],  [2,6,3],  [3,0,0]],
  three: [[1,4,6],   [2,0,0],  [3,5,6]],
};

因为内部数组的所有第一个数字都小于或等于3。 以 4,5... 开头的数组将被忽略。

ramda 有什么方法可以实现这个功能?

我知道您想使用 Ramda,这不是使用该库的解决方案,但可以实现相同的效果。您可以通过将第一个数组值 a[0] 与传递给函数的 maxVal 进行比较来创建一个对象 from entries filtered

const arrays = {
  one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
  two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
  three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};

const filterArrays = (arsObj, maxVal) => {
  return Object.fromEntries(Object.entries(arsObj).map(([k, v]) => {
    return [k, v.filter((a) => a[0] <= maxVal)];
  }));
}

const result = filterArrays(arrays, 3);
console.log(result);

我喜欢 Ramda 的 map 函数,因为它可以遍历对象的属性(因此避免了 Object.fromEntries & Object.entries)并对每个对象应用一个函数。该函数是 filter ,它将内部数组作为参数。赋予filter的功能本身就是gtehead的组合;获取数组的第一个元素并将其与 3:

进行比较
const arrays =
  { one:   [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4,  1, 3]]
  , two:   [[1, 77,  2], [2, 6,  3], [3, 0, 0], [4, 55, 3]]
  , three: [[1,  4,  6], [2, 0,  0], [3, 5, 6], [4,  0, 0]] };

   map(filter(compose(gte(3), head)), arrays);
// ^   ^      ^       ^       ^
// A   B      C       D       E

//=> { one:   [[ 1, 33, 41], [2, 0, 27], [3, 7, 9]]
//=> , two:   [[ 1, 77,  2], [2, 6,  3], [3, 0, 0]]
//=> , three: [[ 1,  4,  6], [2, 0,  0], [3, 5, 6]] }
  • 映射每个 属性 (A);每个数组都传递给 filter (B)
  • 每个内部数组被传递给compose (C)
  • 取每个内部数组的头部(E)与3比较(D)

Scott Christopher 在评论中正确地指出 gte 在部分应用时可能会造成混淆。事实上,整个组合可以用这个简单的 lambda 代替:([x]) => x <= 3.

我也喜欢的替代方案:

map(filter(([x]) => x <= 3), arrays);

我完全赞同@customcommander 的方法, 只是想补充一点,您也可以将 numerical indexes 传递给 R.propSatisfies

const headIs3OrBelow = R.propSatisfies(R.gte(3), 0);
const fn = R.map(R.filter(headIs3OrBelow));

// ===
const data = {
  one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
  two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
  three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};

console.log(
  fn(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>


也同意 gte 和其他类似的方法很难阅读,因为它们有点像 is 3 gte than x 一样向后读......在 Haskell 中你可以这样做:


3 `gte` x

普通方法:

const headIs3OrBelow = ([head]) => head <= 3;

const fn = (data) => Object.entries(data).reduce(
  (res, [k, lists]) => ({ ...res, [k]: lists.filter(headIs3OrBelow) }),
  {},
);

// ===
const data = {
  one: [[1, 33, 41], [2, 0, 27], [3, 7, 9], [4, 1, 3]],
  two: [[1, 77, 2], [2, 6, 3], [3, 0, 0], [4, 55, 3]],
  three: [[1, 4, 6], [2, 0, 0], [3, 5, 6], [4, 0, 0]],
};

console.log(
  fn(data),
);