我尝试清理我的代码。第一个版本使用each_with_index
。在第二个版本中,我尝试使用Enumerable.inject_with_index-construct
压缩代码,我发现here。
它现在有效,但在我看来像第一个代码一样模糊。 更糟糕的是,我不理解元素周围的括号,
中的索引.. .inject(groups) do |group_container, (element,index)|
但他们是必要的
class Array
# splits as good as possible to groups of same size
# elements are sorted. I.e. low elements go to the first group,
# and high elements to the last group
#
# the default for number_of_groups is 4
# because the intended use case is
# splitting statistic data in 4 quartiles
#
# a = [1, 8, 7, 5, 4, 2, 3, 8]
# a.sorted_in_groups(3) # => [[1, 2, 3], [4, 5, 7], [8, 8]]
#
# b = [[7, 8, 9], [4, 5, 7], [2, 8]]
# b.sorted_in_groups(2) {|sub_ary| sub_ary.sum } # => [ [[2, 8], [4, 5, 7]], [[7, 8, 9]] ]
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index do |element, index|
group_number = (index.to_f / average_group_size).floor
groups[group_number] << element
end
groups
end
end
class Array
def sorted_in_groups(number_of_groups = 4)
groups = Array.new(number_of_groups) { Array.new }
return groups if size == 0
average_group_size = size.to_f / number_of_groups.to_f
sorted = block_given? ? self.sort_by {|element| yield(element)} : self.sort
sorted.each_with_index.inject(groups) do |group_container, (element,index)|
group_number = (index.to_f / average_group_size).floor
group_container[group_number] << element
group_container
end
end
end
答案 0 :(得分:27)
这些括号有什么用?
这是红宝石的一个非常好的功能。我把它称为“解构数组赋值”,但它也可能有正式名称。
这是它的工作原理。假设你有一个数组
arr = [1, 2, 3]
然后将此数组分配给名称列表,如下所示:
a, b, c = arr
a # => 1
b # => 2
c # => 3
你看,阵列被“解构”成了它的各个元素。现在,转到each_with_index
。如您所知,它就像常规each
,但也返回索引。 inject
并不关心这一切,它接受输入元素并将它们按原样传递给它。如果input元素是一个数组(来自each_with_index
的elem / index对),那么我们可以在块体中将它分开
sorted.each_with_index.inject(groups) do |group_container, pair|
element, index = pair
# or
# element = pair[0]
# index = pair[1]
# rest of your code
end
或者在块签名中对该数组进行解构。括号中有必要给ruby一个暗示,这是一个需要拆分成几个参数的单个参数。
希望这有帮助。
答案 1 :(得分:7)
lines = %(a b c)
indexes = lines.each_with_index.inject([]) do |acc, (el, ind)|
acc << ind - 1 if el == "b"
acc
end
indexes # => [0]
答案 2 :(得分:1)
这些括号有什么用?
要理解括号,首先需要了解破坏在ruby中的工作原理。最简单的例子我可以想到这个:
1.8.7 :001 > [[1,3],[2,4]].each do |a,b|
1.8.7 :002 > puts a, b
1.8.7 :003?> end
1
3
2
4
您应该知道each
函数如何工作,并且该块接收一个参数。那么当你传递两个参数时会发生什么?它需要第一个元素[1,3]
并尝试将其拆分(破坏)为两个,结果为a=1
和b=3
。
现在,请注入takes two arguments in the block parameter,因此通常看起来像|a,b|
。因此传递像|group_container, (element,index)|
这样的参数我们实际上将第一个作为其他参数,并在另外两个参数中破坏第二个参数(因此,如果第二个参数是[1,3]
,element=1
和{ {1}})。括号是必需的,因为如果我们使用index=3
,我们永远不会知道我们是在破坏第一个还是第二个参数,所以括号用作消歧。
答案 3 :(得分:0)
似乎已经有一些答案给出了很好的解释。我想添加一些关于清晰可读的信息。
除了您选择的解决方案之外,还可以扩展Enumerable并添加此功能。
module Enumerable
# The block parameter is not needed but creates more readable code.
def inject_with_index(memo = self.first, &block)
skip = memo.equal?(self.first)
index = 0
self.each_entry do |entry|
if skip
skip = false
else
memo = yield(memo, index, entry)
end
index += 1
end
memo
end
end
通过这种方式,你可以这样调用inject_with_index
:
# m = memo, i = index, e = entry
(1..3).inject_with_index(0) do |m, i, e|
puts "m: #{m}, i: #{i}, e: #{e}"
m + i + e
end
#=> 9
如果未传递初始值,则将使用第一个元素,因此不会对第一个元素执行块。