Ruby的each_with_index偏移量

86

我能否定义在each_with_index循环迭代器中的索引偏移量? 我的直接尝试失败了:

some_array.each_with_index{|item, index = 1| some_func(item, index) }

编辑:

澄清:我不想要一个数组偏移量,我想让每个_with_index中的索引不从0开始,而是从1开始。


你使用的 Ruby 版本是什么? - fl00r
抱歉没有写信,但我使用的是Ruby 1.9.2。 - Mark
10个回答

111

实际上,Enumerator#with_index 方法接受 offset 作为一个可选参数:

[:foo, :bar, :baz].to_enum.with_index(1).each do |elem, i|
  puts "#{i}: #{elem}"
end

输出:

1: foo
2: bar
3: baz

顺便说一句,我认为它只存在于1.9.2版本中。


2
在1.8.7版本中,只有with_index没有参数,索引从0开始。 - mpapis
实际上,还有一个更短的答案,请看下面我的回答。 - Zack Xu

53
以下是简洁的示例,使用 Ruby 的 Enumerator 类。
[:foo, :bar, :baz].each.with_index(1) do |elem, i|
    puts "#{i}: #{elem}"
end

输出

1: foo
2: bar
3: baz

Array#each返回一个枚举器,而调用Enumerator#with_index返回另一个枚举器,并向其传递一个块。


5

1)最简单的方法是将index替换为index+1,并将其应用于该函数:

some_array.each_with_index{|item, index| some_func(item, index+1)}

但是可能这不是你想要的。

2)接下来你可以做的是在块内定义一个不同的索引j,并使用它代替原始索引:

some_array.each_with_index{|item, i| j = i + 1; some_func(item, j)}

3) 如果您经常使用此方法来使用索引,那么请定义另一个方法:

module Enumerable
  def each_with_index_from_one *args, &pr
    each_with_index(*args){|obj, i| pr.call(obj, i+1)}
  end
end

%w(one two three).each_with_index_from_one{|w, i| puts "#{i}. #{w}"}
# =>
1. one
2. two
3. three


更新

这个回答是几年前回答的,现在已经过时了。对于现代的Ruby来说,Zack Xu的答案会更好。


即使数组中没有更多元素,它仍然会进行迭代,这是一个不好的事情。 - fl00r
@fl00r 真的吗?在我的例子中,它在三个后停止了。 - sawa
但是如果偏移量是2或10呢?在你的情况下,偏移量为零。我的意思是,在你的(3)中没有任何偏移量。 - fl00r
@fl00r,你只需要将我的代码中的+1改为+2+10,它同样有效。 - sawa
天啊,作者编辑了他的帖子,所以他需要索引偏移量而不是数组。 - fl00r
显示剩余2条评论

4
如果some_index有一定的含义,那么考虑使用哈希表而非数组。

4

我遇到了这个问题。

我的解决方案可能不是最好的,但它对我起作用了。

在视图迭代中:

只需要添加:index + 1

对我来说就这些了,因为我没有使用任何索引号的参考,只是展示在列表中。


3
可以的。
some_array[offset..-1].each_with_index{|item, index| some_func(item, index) }
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
some_array[offset..-1].each_with_index{|item, index| index+=offset; some_func(item, index) }

更新

另外,我应该注意到,如果偏移量超过了你的数组大小,它将会抛出一个错误。因为:

some_array[1000,-1] => nil
nil.each_with_index => Error 'undefined method `each_with_index' for nil:NilClass'

我们在这里可以做什么:

 (some_array[offset..-1]||[]).each_with_index{|item, index| some_func(item, index) }

或者预先验证偏移量:

 offset = 1000
 some_array[offset..-1].each_with_index{|item, index| some_func(item, index) } if offset <= some_array.size

这有点hacky(不太正规的)

更新2

既然您更新了问题,现在您不需要数组偏移量,而是需要索引偏移量,因此@sawa的解决方案对您来说将很好地运行。


1

这在每个 Ruby 版本中都可用:

%W(one two three).zip(1..3).each do |value, index|
  puts value, index
end

对于一个通用数组:

a.zip(1..a.length.each do |value, index|
  puts value, index
end

第二个例子中缺少一个括号。 - waferthin

1
Ariel是对的。这是处理这个问题的最佳方式,而且并不那么糟糕。
ary.each_with_index do |a, i|
  puts i + 1
  #other code
end

这是完全可以接受的,比我见过的大多数解决方案都要好。我一直认为这就是 #inject 的用途...哎呀。


1
另一种方法是使用map
some_array = [:foo, :bar, :baz]
some_array_plus_offset_index = some_array.each_with_index.map {|item, i| [item, i + 1]}
some_array_plus_offset_index.each{|item, offset_index| some_func(item, offset_index) }

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接