[1,2,3].partition.inject(0) do |acc, x|
x>2 # this line is intended to be used by `partition`
acc+=x # this line is intended to be used by `inject`
end
我知道我可以使用不同的方法在上面写一节,但这在这里并不重要
我想问一下为什么有人想在“链”的开头使用partition
(或其他方法,如keep_if
,delete_if
)?
在我的示例中,在我链接inject
后,我无法使用partition
。我可以使用each
编写上面的节:
[1,2,3].each.inject(0) do |acc, x|
x>2 # this line is intended to be used by `partition`
acc+=x # this line is intended to be used by `inject`
end
它会是一样的,对吧?
我知道x>2
将partition
丢弃(而不是使用)acc+=x
。只有partition
才能完成这项任务(在这种情况下,总结所有元素)
我只写了那个来展示我的“意图”:我想在链中使用[].partition.inject(0)
,如}.map
。
我知道上面的代码不能像我预期的那样工作,我知道我可以在块之后链接(partition
,如Neil Slater所述)。
我想知道原因,以及keep_if
(以及其他方法,如delete_if
,each
等)何时成为partition
(只返回数组的元素为{{ 1}}在上述情况下做。)
在我的示例中,partition.inject
,partition
变为each
,因为partition
无法采取条件(x>2
)。
但是partition.with_index
(正如Boris Stitnicky所提到的)可以工作(我可以分区数组并使用索引来实现我想要的任何东西):
shuffled_array
.partition
.with_index { |element, index|
element > index
}
PS。这不是关于如何获得大于2的元素之和的问题。
答案 0 :(得分:3)
这是一个有趣的情况。看看你的代码示例,你显然是Ruby的新手,也可能是编程的新手。然而,你设法提出一个非常棘手的问题,基本上涉及Enumerator
类,这是一个最不被公开理解的类,特别是自Enumerator::Lazy
引入以来。对我来说,你的问题很难,我无法提供全面的答案。然而,关于你的代码的评论不适合OP下的评论。这就是我添加这个非答案的原因。
首先,让我们注意一下代码中的一些可怕的东西:
无用的行。在这两个块中,x>2
行无效,因为它的返回值被丢弃。
[1,2,3].partition.inject(0) do |x, acc|
x>2 # <---- return value of this line is never used
acc+=x
end
[1,2,3].each.inject(0) do |x, acc|
x>2 # <---- return value of this line is never used
acc+=x
end
在进一步讨论代码示例时,我会忽略这条无用的行。
无用的#each
方法。编写
[1,2,3].each.inject(0) do |x, acc|
acc+=x
end
这就够了:
[1,2,3].inject(0) do |x, acc|
acc+=x
end
无用地使用#partition
方法。而不是:
[1,2,3].partition.inject(0) do |x, acc|
acc+=x
end
你可以这样写:
[1,2,3].inject(0) do |x, acc|
acc+=x
end
或者,就像我写的那样:
[ 1, 2, 3 ].inject :+
但是,您提出了一个关于在枚举器模式下使用#partition
方法的深层次问题。在讨论了代码的琐碎新手问题之后,我们留下了一个问题:如何使用#partition
,#keep_if
等的枚举器返回版本,或者更确切地说,有趣的方式是什么?使用它们,因为每个人都知道我们可以用它们进行链接:
array = [ *1..6 ]
shuffled_arrray = array.shuffle # randomly shuffles the array elements
shuffled_array
.partition # partition enumerator comes into play
.with_index { |element, index| # method Enumerator#with_index comes into play
element > index # and partitions elements into those greater
} # than their index, and those smaller
也是这样:
e = partition_enumerator_of_array = array.partition
# And then, we can partition the array in many ways:
e.each &:even? # partitions into odd / even numbers
e.each { rand() > 0.5 } # partitions the array randomly
# etc.
一个容易理解的优点是,而不是写更长的时间:
array.partition &:even?
你可以写更短的内容:
e.each &:even?
但我基本上确信枚举器为程序员提供了更多的权力,而不仅仅是链接收集方法和缩短代码。因为不同的调查员做了很多不同的事情。某些内容(例如#map!
或#reject!
)甚至可以修改其运行的集合。在这种情况下,可以想象的是,可以将不同的枚举器与相同的块组合以执行不同的操作。这种能力不仅可以改变块,而且还可以改变它们传递给它的枚举器,它提供了组合能力,这很可能用于使一些其他冗长的代码非常简洁。但我无法提供一个非常有用的具体例子。
总之,Enumerator
类主要用于链接,并且使用链接,程序员并不需要详细检查Enumerator
。但是我怀疑使用Enumerator
的正确习惯可能和参数化子类化的正确习惯一样难以学习。我怀疑我还没有掌握使用枚举器的最有效方法。
答案 1 :(得分:3)
我认为结果[3, 3]
就是你在这里寻找的 - 将数组分成越来越大的数字,然后对每个组进行求和。您似乎对如何将块“规则”赋予两种不同的方法感到困惑,并将两个块合并为一个。
如果您需要多个方法的净效果,每个方法都占用一个块,那么您可以在任何块之后链接,方法是在块关闭后添加.method
,如下所示: }.each
或end.each
另请注意,如果创建分区,则可能需要单独对每个分区求和。为此,您需要链中的额外链接(在本例中为map
):
[1,2,3].partition {|x| x > 2}.map do |part|
part.inject(0) do |acc, x|
x + acc
end
end
# => [3, 3]
(你在注入中也得到了累加器和当前值错误的方法,并且不需要分配给累加器,Ruby会为你做这件事。)
.inject
不再位于方法链中,而是内部一个块。其他块中的块没有问题,事实上你会在Ruby代码中经常看到这个。
我在上面的示例中已经链接了.partition
和.map
。您也可以这样写上面的内容:
[1,2,3].partition do
|x| x > 2
end.map do |part|
part.inject(0) do |acc, x|
x + acc
end
end
。 。 。虽然在使用短块链接时,我个人觉得使用{ }
语法而不是do end
更容易,尤其是在链的开头。
如果一切看起来都很复杂,那么将链的第一部分的结果分配给局部变量通常不会有很高的成本,在这种情况下根本就没有链。
parts = [1,2,3].partition {|x| x > 2}
parts.map do |part|
part.inject(0) do |acc, x|
x + acc
end
end