拉姆达长度很深

时间:2017-06-10 13:42:47

标签: javascript functional-programming lodash ramda.js

我有一个深度为一级的数组,需要计算嵌套数组的长度总和,即长度
试图用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;
&#13;
&#13;
PS:我通过尝试将它应用于日常编码来学习Ramda。

4 个答案:

答案 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>