Javascript 拉姆达深度

Javascript 拉姆达深度,javascript,functional-programming,lodash,ramda.js,Javascript,Functional Programming,Lodash,Ramda.js,我有一个一级深度的数组,需要计算嵌套数组的长度之和,即长度深度。 试图找出一个好的习惯用法来使用Ramda。 我目前的解决方案感觉不够简洁。也许我遗漏了什么。 你能推荐更好的吗 常数arr=[[1]、[2,3]、[4,5,6]] const lengthDeep=右管 R.mapR.道具“长度”, R.sum console.loglengthDeeparr//6 首先,您可以使用R.length而不是R.prop'length'。您还可以考虑对数组进行扁平化,之后所需的结果是: R.pipe

我有一个一级深度的数组,需要计算嵌套数组的长度之和,即长度深度。 试图找出一个好的习惯用法来使用Ramda。 我目前的解决方案感觉不够简洁。也许我遗漏了什么。 你能推荐更好的吗

常数arr=[[1]、[2,3]、[4,5,6]] const lengthDeep=右管 R.mapR.道具“长度”, R.sum console.loglengthDeeparr//6 首先,您可以使用R.length而不是R.prop'length'。您还可以考虑对数组进行扁平化,之后所需的结果是:
R.pipe(R.flatten, R.length)
首先,您可以使用R.length而不是R.prop'length'。您还可以考虑对数组进行扁平化,之后所需的结果是:
R.pipe(R.flatten, R.length)

虽然这是一个非常直截了当和简单的问题,但我认为它缓解了一个有趣的问题

到目前为止,有三个建议。我跳过@ftor的回答,因为它忽略了你关于这是学习拉姆达的一部分的评论。但我要包括他对折叠的评论

以下是解决方案:

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);
注意,我从管道切换到了组合。当函数适合一行时,我通常使用compose,但我不认为pipe和compose是根本不同的解决方案

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

版本A R.composeR.sum,R.mapR.length是最简单的,我相信它与问题的原始表示最接近:我们希望找到嵌套数组的长度之和。这个版本最简单:它找到这些长度,然后将它们相加。这是您的版本,通过@trincot观察到R.length将取代R.prop'length'来增强。这是我会选择的。这很简单,它的作用显而易见

版本B R.composeR.length,R.Flatte对应于问题的一个非常不同的概念。它回答了这样一个问题,如果我把所有这些数组合并成一个,需要多长时间?据我所知,它的唯一优点是它是最简单的代码。不利的一面是,它可能需要更长的运行时间,而且肯定需要更多的空间

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

同样,我会选择版本A,除非有重要的事情促使我切换到版本C。不过,这似乎不太可能


所有这些都可能是对@ftor评论的一种非常冗长的反驳:在实际折叠数据结构时不应该使用map。我想说的是,您应该使用最简单的代码来匹配您的问题心理模型。这必须通过其他考虑因素(如性能)加以调整,但这应该是默认设置。我对这个问题的概念完全符合“取所有长度并将它们相加”模型。

虽然这是一个非常简单明了的问题,但我认为它缓解了一个有趣的问题

到目前为止,有三个建议。我跳过@ftor的回答,因为它忽略了你关于这是学习拉姆达的一部分的评论。但我要包括他对折叠的评论

以下是解决方案:

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);
注意,我从管道切换到了组合。当函数适合一行时,我通常使用compose,但我不认为pipe和compose是根本不同的解决方案

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

版本A R.composeR.sum,R.mapR.length是最简单的,我相信它与问题的原始表示最接近:我们希望找到嵌套数组的长度之和。这个版本最简单:它找到这些长度,然后将它们相加。这是您的版本,通过@trincot观察到R.length将取代R.prop'length'来增强。这是我会选择的。这很简单,它的作用显而易见

版本B R.composeR.length,R.Flatte对应一个非常不同的conce 这是问题的症结所在。它回答了这样一个问题,如果我把所有这些数组合并成一个,需要多长时间?据我所知,它的唯一优点是它是最简单的代码。不利的一面是,它可能需要更长的运行时间,而且肯定需要更多的空间

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

同样,我会选择版本A,除非有重要的事情促使我切换到版本C。不过,这似乎不太可能


所有这些都可能是对@ftor评论的一种非常冗长的反驳:在实际折叠数据结构时不应该使用map。我想说的是,您应该使用最简单的代码来匹配您的问题心理模型。这必须通过其他考虑因素(如性能)加以调整,但这应该是默认设置。我对这个问题的概念完全符合“取长补短”模型。

这里有另一种方法,您可以使用一个名为mapReduce的小助手来实现它——我们可以使用Ramda的curry实现它,这样它将像其他Rambda库成员一样共享一个神奇的curry界面

mapReduce有效地获取一个映射函数m和一个缩减函数r,并创建一个新的缩减函数。这是一个有用的泛型函数,因为它可以在您希望生成减缩器的任何地方使用

作为一个额外的好处,这个解决方案将只迭代输入数组一次,以满足计算答案的最低要求

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

这里有另一种方法,您可以使用一个名为mapReduce的小助手来实现它——我们可以使用Ramda的curry来实现它,这样它将像其他Rambda库成员一样共享一个神奇的curry界面

mapReduce有效地获取一个映射函数m和一个缩减函数r,并创建一个新的缩减函数。这是一个有用的泛型函数,因为它可以在您希望生成减缩器的任何地方使用

作为一个额外的好处,这个解决方案将只迭代输入数组一次,以满足计算答案的最低要求

// 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}
常数arr=[[1]、[2,3]、[4,5,6]] const lengthDeep=R.reduceR.useWithR.add,[R.identity,R.prop'length',0 console.loglengthDeeparr//6 常数arr=[[1]、[2,3]、[4,5,6]] const lengthDeep=R.reduceR.useWithR.add,[R.identity,R.prop'length',0 console.loglengthDeeparr//6
看起来很棒!谢谢唯一的缺点可能是大型阵列的性能。我的意思是,为了得到长度,这太难了。看起来很棒!谢谢唯一的缺点可能是大型阵列的性能。我的意思是,这太多了,不能仅仅为了得到长度而展平。在实际折叠数据结构时,不应该使用map。在实际折叠数据结构时,不应该使用map。嘿,斯科特,我的评论只是基于观点,不值得适当的回应。当然,OP可以用一个中间数组组成自己的折叠。我想说的是,最好的代码不一定是最简洁的。@ftor,我一开始并没有想过要回应你的评论。只有当我写下大部分答案时,我才意识到它与你的评论相矛盾。我当然不认为总的来说这是个坏主意,我很喜欢你对问题的分析。我完全同意简洁不是代码的主要优点。谢谢你的详细解释。我没想到这个问题会有这么多的活动。@OlegMaslov如果你认为你得到了足够的答案,请接受其中一个答案:-嘿,Scott,我的评论只是基于观点,不值得适当的回答。当然,OP可以用一个中间数组组成自己的折叠。我想说的是,最好的代码不一定是最简洁的。@ftor,我并没有启动ou
我不想回应你的评论。只有当我写下大部分答案时,我才意识到它与你的评论相矛盾。我当然不认为总的来说这是个坏主意,我很喜欢你对问题的分析。我完全同意简洁不是代码的主要优点。谢谢你的详细解释。我没想到这个问题会有这么多的活动。@OlegMaslov如果你认为你得到了足够的答案,请接受其中一个答案:-地图传感器是这里的正确工具。由于这在第二个参数中本质上是函数组合,我想知道是否有比mapReduce或mapper更通用的名称。我还想知道我们是否可以使用右折叠来简化代码,其中累加器是reducer的第二个参数,我们可以简单地在第一个参数上组合。当然,这需要一个现成的解决方案。我来试一试。@ftor,我想这可能就是你所描述的:–是吗?我不太清楚你在那里做了什么。不过看起来很酷。实际上,我的意思是使用Array.prototype.reduceRight和固定的参数顺序。事实上,它已被破坏:谢谢您的回复。但对我来说,它看起来极其复杂。对于一个已经专注于函数式编程并习惯于这样思考的人来说,这可能没什么问题。map传感器是这里的正确工具。由于这在第二个参数中本质上是函数组合,我想知道是否有比mapReduce或mapper更通用的名称。我还想知道我们是否可以使用右折叠来简化代码,其中累加器是reducer的第二个参数,我们可以简单地在第一个参数上组合。当然,这需要一个现成的解决方案。我来试一试。@ftor,我想这可能就是你所描述的:–是吗?我不太清楚你在那里做了什么。不过看起来很酷。实际上,我的意思是使用Array.prototype.reduceRight和固定的参数顺序。事实上,它已被破坏:谢谢您的回复。但对我来说,它看起来极其复杂。对于一个已经专注于函数式编程并习惯于用这种方式思考的人来说,这可能没什么问题。