ruby - 链接分区,keep_if 等

标签 ruby chaining

[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_ifdelete_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).
我知道上面的代码不会像我预期的那样工作,而且我知道我可以在 block 之后链接(}.map,如 Neil Slater 所提到的)。

我想知道为什么以及何时 partition(以及其他方法,如 keep_ifdelete_if 等)变为 each(在上述情况下,只返回数组的元素,就像 partition 所做的那样)。
在我的示例中,partition.injectpartition 变成了 each 因为 partition 不能接受条件 (x> 2).
但是 partition.with_index(正如 Boris Stitnicky 所提到的)有效(我可以对数组进行分区并为我想要的任何东西使用索引):

shuffled_array
  .partition                        
  .with_index { |element, index|    
    element > index                 
}

附言。这不是关于如何获取大于 2 的元素之和的问题。

最佳答案

这是一个有趣的情况。查看您的代码示例,您显然是 Ruby 的新手,也许还不熟悉编程。然而,您设法提出了一个非常困难的问题,该问题基本上与 Enumerator 类有关,它是公众了解最少的类之一,特别是自从引入 Enumerator::Lazy 以来。对我来说,你的问题很难,我无法提供全面的答案。然而,关于您的代码的评论不适合 OP 下的评论。这就是我添加此非答案的原因。

首先,让我们注意到您的代码中有一些糟糕的地方:

无用行。在这两个 block 中,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!,甚至可以修改它们操作的集合。在这种情况下,可以想象可以将不同的枚举器与同一个 block 组合起来做不同的事情。这种不仅可以改变 block ,还可以改变传递给它们的枚举器的能力提供了组合能力,这很可能用于使一些原本冗长的代码变得非常简洁。但我无法提供一个非常有用的具体示例。

总而言之,Enumerator类在这里主要是为了链接,而要使用链接,程序员并不需要对Enumerator进行详细的理解。但我怀疑关于使用 Enumerator 的正确习惯可能与例如参数化子类化的正确习惯一样难以学习。我怀疑我还没有掌握使用枚举器的最强大方法。

关于ruby - 链接分区,keep_if 等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21936171/

相关文章:

ruby - Ruby 中的数组哈希

afnetworking - 使用 ReactiveCocoa 组合多个网络请求

jQuery 链接 .load() 请求?

ruby-on-rails - 从新终端访问 Rails 应用程序时,所有 gem 都将被删除

javascript - 延迟的 promise 链不起作用

javascript - 如何在 javascript 中链接但在两者之间获得值(value)

javascript - 在对象内的回调中从一个方法返回值到第二个方法

ruby - 是否可以在 Ruby 中定义一个名称以 : (colon)? 结尾的方法

ruby-on-rails - 在 Ruby on Rails 中创建对象时,您更喜欢哪种保存方法,为什么?

ruby-on-rails - Vim 中的 ruby​​ 代码格式错误