我有一个深度为一级的数组,需要计算嵌套数组的长度总和,即长度。
试图用Ramda来找出一个很好的惯用方法
我目前的解决方案并不够简洁。可能我错过了一些东西
你能建议更好吗?
const arr = [[1], [2, 3], [4, 5, 6]]
const lengthDeep = R.pipe(
R.map(R.prop('length')),
R.sum
)
console.log(lengthDeep(arr)) // 6

<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>
&#13;
答案 0 :(得分:2)
首先,您可以使用R.length
代替R.prop('length')
。您还可以考虑展平数组,之后所需的结果是:
R.pipe(R.flatten, R.length)
答案 1 :(得分:2)
虽然这是一个非常简单明了的问题,但我认为这让人感到宽慰。
目前有三条建议。我正在跳过@ ftor的答案,因为它忽略了你对这是学习Ramda的一部分的评论。但我包括他关于折叠的评论。
以下是解决方案:
const lengthDeep = R.compose(R.sum, R.map(R.length));
const lengthDeep = R.compose(R.length, R.flatten);
const lengthDeep = R.reduce((total, xs) => total + R.length(xs), 0);
(请注意,我已从pipe
切换为compose
。当函数适用于单行时,我通常会使用compose
但我不会想到{{1} }和pipe
作为根本不同的解决方案。)
这些对应于对该问题的不同理解。
版本A (compose
)是最直接的,我相信它最贴近问题的原始呈现:我们希望找到&#34;总和嵌套数组的长度&#34;。这个版本最直接:它找到那些长度,然后将它们加在一起。 (这是你的版本增强了{trincot&{39}} R.compose(R.sum, R.map(R.length))
代替R.length
所做的观察。)这是我会选择的。这很简单,它的作用很明显。
版本B (R.prop('length')
)对应于一个非常不同的问题概念。它回答了这个问题,&#34;如果我将所有这些数组合并为一个,它会有多长时间?&#34;据我所知,唯一的优势是它是最简单的代码。不利的一面是,运行可能需要更长的时间,而且肯定需要更多的空间。
版本C (R.compose(R.length, R.flatten)
)涉及另一个概念。描述此解决方案的最佳方式是使用递归描述。空数组数组的深度为零。第一个元素长度为R.reduce((total, xs) => total + R.length(xs), 0)
的数组数组的深度为n
加上数组数组其余部分的深度。如果您对问题的看法如此,那么此版本可能适合您。还有一次你可能会选择使用它:虽然我没有经过测试,但我认为它会更高效,因为它只会在外部列表上循环一次。因此,如果您发现此函数是代码中的瓶颈(您在引入任何性能优化之前都会测试性能,对吗?),您可能会切换到它,即使代码实际上更复杂。 (我不知道它是否有合理的免费版本。我看不到一个简单的版本,这已经足够可读了。)
同样,我会选择版本A ,除非有重要提示我切换到版本C 。但这似乎不太可能。
所有这些可能是一种非常冗长的方式,不同意@ ftor的评论:&#34;当你实际n
数据时,你不应该使用map
。结构&#34;我会说你应该使用最符合问题心理模型的代码。这必须通过性能等其他考虑因素来缓和,但它应该是默认值。我对这个问题的概念完全符合&#34;采取所有长度并将它们加在一起&#34;模型。
答案 2 :(得分:0)
这是另一种方法,你可以使用一个名为mapReduce
的小助手来实现它 - 我们可以使用Ramda的curry
来实现它,这样它就像其他Rambda库成员一样共享一个神奇的咖喱界面。
mapReduce
有效地使用映射函数m
和缩减函数r
并创建新的缩减函数。这是一个有用的通用函数,因为它可以在任何你想要生成reducers的地方使用
作为一个额外的好处,这个解决方案只会通过输入数组迭代一次(计算答案的最低要求)
// mapReduce :: (a -> b) -> ((c, b) -> c) -> ((c, a) -> c)
const mapReduce = curry ((m, r) =>
(x, y) => r (x, m (y)))
// deepLength :: [[a]] -> Integer
const deepLength = xs =>
reduce (mapReduce (length, add), 0, xs)
// arr :: [[Integer]]
const arr = [[1], [2, 3], [4, 5, 6]]
console.log (deepLength (arr))
// 6
为了展示mapReduce
的多样化效用,我将向您展示当它们稍微复杂时它能够处理的事情 - 同时仍然保持可读的程序
// mapReduce :: (a -> b) -> ((c, b) -> c) -> ((c, a) -> c)
const mapReduce = curry ((m, r) =>
(x, y) => r (x, m (y)))
// omap :: (a -> b) -> {k : a} -> {k : b}
const omap = curry ((f, o) =>
reduce (mapReduce (k => ({ [k]: f(o[k]) }), Object.assign), {}, keys(o)))
console.log (omap (add(10), {a: 1, b: 2, c: 3}))
// {"a": 11, "b": 12, "c": 13}
答案 3 :(得分:0)
const arr = [[1], [2, 3], [4, 5, 6]]
const lengthDeep = R.reduce(R.useWith(R.add, [R.identity, R.prop('length')]), 0)
console.log(lengthDeep(arr)) // 6
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>