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
of course I can return index by array.index[element]
but I am searching for more natural solution. Like proxy_owner
in Rails associations
Ruby 1.8.7
What I want to output? I want to return object wich I iterating (array in my case), also number of iteration (index in case of each_with_index)next and priviouse开发者_JAVA技巧 element of iteration.
As input I have got an Array and iterator (each, map, inject etc)
Use Enumerable#each_cons
. The following is a copy from ruby1.8.7 rdoc. It should work on ruby 1.8.7.
- each_cons(n) {...}
- each_cons(n)
Iterates the given block for each array of consecutive elements. If no block is given, returns an enumerator.
With this , you can give an array:
['a', 'b', 'c', 'd', 'e'].each_cons(3).to_a
# => ["a", "b", "c"], ["b", "c", "d"], ["c", "d", "e"]]
or do:
['a', 'b', 'c', 'd', 'e'].each_cons(3) {|previous, current, nekst|
puts "#{previous} - #{current} - #{nekst}"
}
# => a - b - c
# => b - c - d
# => c - d - e
If you want 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
You can pass the array to other enumerators quite generally, for example, with inject
:
['a', 'b', 'c', 'd', 'e'].each_cons(3).to_a.inject(''){|str, (previous, current, nekst)|
str << previous+current+nekst
}
# => "abcbcdcde"
In ruby1.8, there is each_with_index
.
If you want that on other iterators like inject
, map
, ..., and if you are using ruby1.9, there is Enumerator#with_index
method that you can attach to various iterators.
Enumerator#with_index
Ruby's each_with_index
functionality can be recreated easily:
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
# >>
Once you know the index for the current object you can peek into the array you're iterating over and get the previous and next values easily.
So, you could do:
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
Can't test, but if remember correctly:
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]]
Replace inject with select, reject or whatever. With Ruby 1.9:
p a.each_with_index.inject([]){ |m,args| m<<args }
Edit: This is for 1.9, I saw now that your question explicitly mentions 1.8.7. I'll leave it here for reference, but if it disturbs anyone I can delete it.
sawa already pointed out Enumerator#with_index
:
http://www.ruby-doc.org/core/classes/Enumerator.html#M000303
Examples:
>> [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
Also related to this question are Enumerator#next
and Enumerator#peek
, which will return the next object in the enumerator, with respectively without moving the internal position forward.
http://www.ruby-doc.org/core/classes/Enumerator.html#M000307
http://www.ruby-doc.org/core/classes/Enumerator.html#M000308
精彩评论