使用 Ramda 过滤每个内部属性数组
Posted
技术标签:
【中文标题】使用 Ramda 过滤每个内部属性数组【英文标题】:Filter each inner property arrays with Ramda 【发布时间】:2021-10-11 21:38:49 【问题描述】:我有一个这样的对象:
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 以什么方式拥有此功能?
【问题讨论】:
【参考方案1】:我了解您想使用 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);
【讨论】:
谢谢@axtck,只是我们尝试“强制”Ramda。它有助于进一步利用编程的功能方法。我有点喜欢它,但有时它会更耗时。【参考方案2】:我喜欢 Ramda 的 map
函数,因为它可以迭代对象的属性(因此避免了 Object.fromEntries
和 Object.entries
)并将函数应用于每个对象。该函数是filter
,它将内部数组作为参数。赋予filter
的函数本身就是gte
和head
的组合;获取数组的第一个元素并将其与 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 在 cmets 中正确指出,gte
在部分应用时可能会令人困惑。事实上,整个组合都可以用这个简单的 lambda 替换:([x]) => x <= 3
。
我也喜欢的替代解决方案:
map(filter(([x]) => x <= 3), arrays);
【讨论】:
R.gte
和朋友不幸因在部分应用时会引起混乱而臭名昭著。也许是主观的,但为了便于阅读,我建议用 lambda 替换提供给R.filter
的参数以实现相同的效果(例如([x]) => x <= 3
)
@ScottChristopher 同意 100%。我添加了您建议的替代答案。谢谢;)【参考方案3】:
我完全赞同@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),
);
【讨论】:
以上是关于使用 Ramda 过滤每个内部属性数组的主要内容,如果未能解决你的问题,请参考以下文章
markdown 使用ramda通过嵌套值过滤对象数组:有时您无权访问后端,并且您希望过滤来自