拉姆达长度很深

问题描述 投票:1回答:4

我有一个深度为一级的数组,需要计算嵌套数组的长度之和,即深度。 试图找出一个很好的惯用方法来做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>

PS: I'm learning Ramda by trying to apply it to everyday coding.
javascript functional-programming lodash ramda.js
4个回答
2
投票

首先,你可以使用R.length而不是R.prop('length')。您还可以考虑展平数组,之后所需的结果是:

R.pipe(R.flatten, R.length)

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,但我不认为pipecompose是根本不同的解决方案。)

这些对应于对问题的不同理解。

版本A(R.compose(R.sum, R.map(R.length)))是最直接的,我相信它最接近问题的原始表示:我们想要找到“嵌套数组的长度之和”。这个版本最直接:它找到那些长度,然后将它们加在一起。 (这是你的版本增强了@ trincot的观察,R.length将代替R.prop('length')。)这是我会选择的。这很简单,它的作用很明显。

版本B(R.compose(R.length, R.flatten))对应于一个非常不同的问题概念。它回答了这个问题,“如果我将所有这些数组合并为一个,它会持续多长时间?”据我所知,唯一的优势是它是最简单的代码。在缺点方面,它可能需要更长的时间才能运行,并且肯定需要更多的空间。

版本C(R.reduce((total, xs) => total + R.length(xs), 0))涉及另一个概念。描述此解决方案的最佳方式是使用递归描述。空数组数组的深度为零。第一个元素长度为n的数组数组的深度长度为n加上数组数组其余部分的深度。如果您对问题的看法如此,那么此版本可能适合您。还有一次你可能会选择使用它:虽然我没有测试过,但我认为它会更高效,因为它只会在外部列表上循环一次。因此,如果您发现此函数是代码中的瓶颈(您在引入任何性能优化之前都会测试性能,对吗?),您可能会切换到它,即使代码实际上更复杂。 (我不知道它是否有一个合理的无点版本。我看不到一个简单的版本,这已经足够可读了。)

同样,我会选择版本A,除非有一些重要提示我切换到版本C.但这似乎不太可能。


所有这些可能是一种非常冗长的方式,不同意@ ftor的评论:“当你实际上map数据结构时,你不应该使用fold。”我会说你应该使用最符合问题心理模型的代码。这必须通过性能等其他考虑因素来缓和,但它应该是默认值。我对这个问题的概念完全符合“全力以赴,将它们加在一起”的模式。


0
投票

这是另一种方法,你可以使用一个名为mapReduce的小助手来实现它 - 我们可以使用Ramda的curry实现它,这样它就像其他Rambda库成员一样共享一个神奇的咖喱界面。

mapReduce有效地采用映射函数m和减少函数r并创建一个新的约简函数。这是一个有用的通用函数,因为它可以在任何您希望生成reducer的地方使用

作为一个额外的好处,这个解决方案只会通过输入数组迭代一次(计算答案的最低要求)

// 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}

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>
© www.soinside.com 2019 - 2024. All rights reserved.