Ruby each_with_index ofset


84

Each_with_index döngü yineleyicisinde indeksin ofsetini tanımlayabilir miyim? Basit girişimim başarısız oldu:

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

Düzenle:

Açıklama: Bir dizi uzaklığı istemiyorum each_with_index içindeki dizinin 0'dan başlamasını değil, örneğin 1 olmasını istiyorum.


hangi Ruby sürümünü kullanıyorsunuz?
fl00r

Yazmadığım için üzgünüm ama Ruby 1.9.2 kullanıyorum
Mark

Yanıtlar:


110

Aslında, Enumerator#with_indexofseti isteğe bağlı bir parametre olarak alır:

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

çıktılar:

1: foo
2: bar
3: baz

BTW, bence sadece 1.9.2'de var.


2
1.8.7'de sadece with_indexparametreler yok, dizinler0
mpapis

aslında daha da kısa bir cevap mümkün, lütfen aşağıdaki benimkine bakın.
Zack Xu

50

Aşağıdakiler, Ruby'nin Numaralandırıcı sınıfını kullanarak kısa ve özdür.

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

çıktı

1: foo
2: bar
3: baz

Dizi # her biri bir numaralandırıcı döndürür ve Enumerator # ile_index çağrısı, bloğun geçirildiği başka bir numaralandırıcı döndürür.


5

1) En basit olanı, işlevi index+1yerine ikame indexetmektir:

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

ama muhtemelen istediğin bu değil.

2) Yapabileceğiniz bir sonraki şey j, blok içinde farklı bir dizin tanımlamak ve orijinal dizin yerine bunu kullanmaktır:

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

3) İndeksi bu şekilde sıklıkla kullanmak istiyorsanız, başka bir yöntem tanımlayın:

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


Güncelleme

Birkaç yıl önce cevaplanan bu cevap artık geçerliliğini yitirmiştir. Modern Ruby'ler için, Zack Xu'nun cevabı daha iyi sonuç verecektir.


o dizi de artık unsurlar var sonra bile itarate edeceğini kötü bir şey
fl00r

@ fl00r Gerçekten mi? Benim örneğimde, üçten sonra duruyor.
sawa

Ancak ofset 2 veya 10 ise? Sizin durumunuzda ofset sıfırdır. Demek istediğim, burada (3)
fl00r

@ Sadece değiştirmek fl00r +1benim kodunda +2veya +10. Çalışıyor.
sawa

OMG, yazar yazısını düzenledi, bu yüzden diziye değil dizin ofsetine ihtiyacı var.
fl00r

4

Bir some_indexşekilde anlamlıysa, dizi yerine karma kullanmayı düşünün.


4

Ben onunla karşılaştım.

Benim çözümüm gerekli değil, en iyisi ama benim için işe yaradı.

Görünüm yinelemesinde:

sadece şunu ekleyin: dizin + 1

Hepsi benim için, çünkü bu indeks numaralarına herhangi bir referans kullanmıyorum, sadece bir listede göstermek için kullanıyorum.


3

Evet yapabilirsin

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) }

UPD

Ayrıca, ofset Array boyutunuzdan fazlaysa, bir hata oluşturacağını fark etmeliyim. Çünkü:

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

Burada ne yapabiliriz:

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

Veya ofseti geçersiz kılmak için:

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

Bu biraz karmaşık

UPD 2

Sorunuzu güncellediğiniz sürece ve şimdi Dizi ofsetine ihtiyacınız yok, ancak endeks ofsetine ihtiyacınız var, böylece @sawa çözümü sizin için iyi çalışacaktır


1

Ariel haklı. Bunu halletmenin en iyi yolu bu ve o kadar da kötü değil

ary.each_with_index do |a, i|
  puts i + 1
  #other code
end

Bu tamamen kabul edilebilir ve bunun için gördüğüm çözümlerin çoğundan daha iyi. Her zaman # enjeksiyonun bunun için olduğunu düşünmüşümdür ...


1

Başka bir yaklaşım kullanmaktır 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) }

1

Bu, her Ruby versiyonunda işe yarar:

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

Ve genel bir dizi için:

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

ikinci örnekte bir parantez eksik.
waferthin

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.