迭代时返回迭代对象和索引

时间:2011-03-26 19:52:42

标签: ruby

array = [1,2,3,{:name => "Peter"}, "hello"]
array.each do |element| # it can be "inject", "map" or other iterators
  # How to return object "array" and position of "element"
  # also next and priviouse "element"
end

当然我可以通过array.index[element]返回索引,但我正在寻找更自然的解决方案。与Rails关联中的proxy_owner一样

Ruby 1.8.7

我想要输出什么?我希望返回我迭代的对象(在我的情况下是数组),也是迭代次数(在each_with_index的情况下为索引)next和迭代的priviouse元素。

作为输入,我有一个数组和迭代器(每个,映射,注入等)

5 个答案:

答案 0 :(得分:6)

使用Enumerable#each_cons。以下是ruby1.8.7 rdoc的副本。它应该适用于ruby 1.8.7。


  • each_cons(n){...}
  • each_cons(n)的

为每个连续元素数组迭代给定的块。如果没有给出块,则返回枚举器。


有了这个,你可以给出一个数组:

['a', 'b', 'c', 'd', 'e'].each_cons(3).to_a

# => ["a", "b", "c"], ["b", "c", "d"], ["c", "d", "e"]]

或做:

['a', 'b', 'c', 'd', 'e'].each_cons(3) {|previous, current, nekst|
    puts "#{previous} - #{current} - #{nekst}"
}

# => a - b - c
# => b - c - d
# => c - d - e

如果你想要indice,

['a', 'b', 'c', 'd', 'e'].each_cons(3).to_a.each_with_index {|(previous, current, nekst), i|
    puts "#{i + 1}. #{previous} - #{current} - #{nekst}"
}

# => 1. a - b - c
# => 2. b - c - d
# => 3. c - d - e

您可以通常将数组传递给其他枚举器,例如inject

['a', 'b', 'c', 'd', 'e'].each_cons(3).to_a.inject(''){|str, (previous, current, nekst)|
    str << previous+current+nekst
}

# => "abcbcdcde"

答案 1 :(得分:5)

在ruby1.8中,有each_with_index

如果你想在injectmap,...等其他迭代器上使用它,并且如果你使用的是ruby1.9,那么有Enumerator#with_index方法可以附加到各种迭代器。

Enumerator#with_index

答案 2 :(得分:3)

可以轻松地重新创建Ruby的each_with_index功能:

ary = %w[zero one two three]
ary.zip((0 .. (ary.size - 1)).to_a).to_a # => [["zero", 0], ["one", 1], ["two", 2], ["three", 3]]

ary.zip((0 .. (ary.size - 1)).to_a).each do |a, i|
  puts "this element: #{a}"
  puts "previous element: #{ary[i - 1]}" if (i > 0)
  puts "next element: #{ary[i + 1]}" if (i < (ary.size - 1))
  puts
end
# >> this element: zero
# >> next element: one
# >> 
# >> this element: one
# >> previous element: zero
# >> next element: two
# >> 
# >> this element: two
# >> previous element: one
# >> next element: three
# >> 
# >> this element: three
# >> previous element: two
# >> 

一旦知道了当前对象的索引,就可以查看正在迭代的数组并轻松获取上一个和下一个值。

所以,你可以这样做:

module Enumerable
  def my_each_with_index
    self.zip((0 .. (self.size - 1)).to_a).each do |a, i|
      yield a, i
    end
  end
end

ary.my_each_with_index { |a,i| puts "index: #{i} element: #{a}" }
# >> index: 0 element: zero
# >> index: 1 element: one
# >> index: 2 element: two
# >> index: 3 element: three

答案 3 :(得分:1)

无法测试,但如果记得正确:

a = [4, 3, 3, 1, 6, 6,1]
p a.enum_for(:each_with_index).inject([]){ |m,args| m<<args }
#=> [[4, 0], [3, 1], [3, 2], [1, 3], [6, 4], [6, 5], [1, 6]]

用select,reject或者其他替换注入。使用Ruby 1.9:

p a.each_with_index.inject([]){ |m,args| m<<args }

答案 4 :(得分:1)

编辑:这是1.9,我现在看到你的问题明确提到1.8.7。我会把它留在这里作为参考,但如果它扰乱任何人我可以删除它。

sawa已经指出Enumerator#with_index

http://www.ruby-doc.org/core/classes/Enumerator.html#M000303

示例:

>> [1,2,3].map.with_index { |x, i| [x,i] }
=> [[1, 0], [2, 1], [3, 2]]
>> [1,2,3].each_cons(2).with_index { |(x, y), i| p [x,y,i] }
[1, 2, 0]
[2, 3, 1]
=> nil

此问题还涉及Enumerator#nextEnumerator#peek,它将返回枚举器中的下一个对象,分别不向前移动内部位置。

http://www.ruby-doc.org/core/classes/Enumerator.html#M000307

http://www.ruby-doc.org/core/classes/Enumerator.html#M000308