Возврат итерирующего объекта и индекса при итерации - PullRequest
4 голосов
/ 26 марта 2011
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], но я ищу более естественное решение. Как proxy_owner в ассоциациях Rails

Рубин 1,8,7

Что я хочу вывести? Я хочу вернуть объект, который я повторяю (массив в моем случае), а также номер итерации (индекс в случае each_with_index) следующий и личный элемент итерации.

В качестве входных данных у меня есть массив и итератор (каждый, карта, инжект и т. Д.)

Ответы [ 5 ]

6 голосов
/ 26 марта 2011

Используйте Enumerable#each_cons. Ниже приведена копия с ruby1.8.7 rdoc . Должен работать на ruby ​​1.8.7.


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

Повторяет данный блок для каждого массива последовательных элементов. Если блок не указан, возвращает перечислитель.


С этим вы можете дать массив:

['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"
5 голосов
/ 26 марта 2011

В ruby1.8 есть each_with_index.

Если вы хотите это на других итераторах, таких как inject, map, ..., и если вы используете ruby1.9, естьэто Enumerator#with_index метод, который вы можете присоединить к различным итераторам.

Enumerator # with_index

3 голосов
/ 27 марта 2011

Ruby's 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
1 голос
/ 27 марта 2011

Edit: это для 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#next и Enumerator#peek, которые будут возвращать следующий объект вперечислитель, соответственно без перемещения внутренней позиции вперед.

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

http://www.ruby -doc.org / ядро ​​/ классов / Enumerator.html # M000308

1 голос
/ 27 марта 2011

Не могу проверить, но если помните правильно:

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]]

Заменить инъекцию на выбор, отклонение или что-то еще. С Ruby 1.9:

p a.each_with_index.inject([]){ |m,args| m<<args }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...