Ruby each_with_index offset


84

Tôi có thể xác định độ lệch của chỉ mục trong trình lặp vòng lặp each_with_index không? Nỗ lực chuyển tiếp thẳng của tôi không thành công:

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

Biên tập:

Làm rõ: Tôi không muốn có sự bù đắp mảng Tôi muốn rằng chỉ mục bên trong each_with_index không bắt đầu từ 0 mà là 1.


bạn sử dụng phiên bản Ruby nào?
fl00r

Xin lỗi vì tôi không viết, nhưng tôi sử dụng Ruby 1.9.2
Đánh dấu

Câu trả lời:


110

Trên thực tế, Enumerator#with_indexnhận offset như một tham số tùy chọn:

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

kết quả đầu ra:

1: foo
2: bar
3: baz

BTW, tôi nghĩ rằng nó chỉ có trong 1.9.2.


2
trong 1.8.7 nó chỉ with_indexkhông có tham số, chỉ số từ0
mpapis

thực sự, một câu trả lời thậm chí còn ngắn hơn là có thể, vui lòng xem phần của tôi bên dưới.
Zack Xu

50

Sau đây là ngắn gọn, sử dụng lớp Enumerator của Ruby.

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

đầu ra

1: foo
2: bar
3: baz

Mỗi mảng # trả về một liệt kê và gọi Enumerator # với_index trả về một liệt kê khác, mà một khối được chuyển đến.


5

1) Đơn giản nhất là thay thế index+1thay vì indexhàm:

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

nhưng có lẽ đó không phải là điều bạn muốn.

2) Điều tiếp theo bạn có thể làm là xác định một chỉ mục khác jtrong khối và sử dụng nó thay cho chỉ mục ban đầu:

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

3) Nếu bạn muốn sử dụng chỉ mục theo cách này thường xuyên, hãy xác định một phương pháp khác:

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


Cập nhật

Câu trả lời này, đã được trả lời cách đây vài năm, bây giờ đã lỗi thời. Đối với Hồng ngọc hiện đại, câu trả lời của Zack Xu sẽ hoạt động tốt hơn.


điều xấu mà nó sẽ itarate ngay cả sau khi không có yếu tố hơn trong mảng
fl00r

@ fl00r Thật không? Trong ví dụ của tôi, nó dừng sau ba.
sawa

Nhưng nếu bù đắp là 2 hay 10? Trong trường hợp của bạn, bù đắp bằng không. Ý tôi là ở đây không có bất kỳ sự bù đắp nào trong (3) của bạn
fl00r

@ fl00r Bạn chỉ cần thay đổi +1mã của tôi thành +2hoặc +10. Nó cũng hoạt động.
sawa

OMG, tác giả đã chỉnh sửa bài viết của mình, vì vậy anh ấy cần bù chỉ số chứ không phải mảng.
fl00r

4

Nếu some_indexcó ý nghĩa bằng cách nào đó, thì hãy cân nhắc sử dụng hàm băm thay vì một mảng.


4

Tôi đã chạy vào nó.

Giải pháp của tôi không cần thiết là tốt nhất, nhưng nó chỉ phù hợp với tôi.

Trong chế độ xem lặp lại:

chỉ cần thêm: index + 1

Đó là tất cả đối với tôi, vì tôi không sử dụng bất kỳ tham chiếu nào đến các số chỉ mục đó mà chỉ để hiển thị trong danh sách.


3

Có, bạn có thể

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

Ngoài ra, tôi nên lưu ý rằng nếu bù đắp nhiều hơn kích thước Mảng của bạn, nó sẽ xảy ra lỗi. Bởi vì:

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

Chúng ta có thể làm gì ở đây:

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

Hoặc để xác thực trước phần bù:

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

Đây là một chút hacky

CẬP NHẬT 2

Theo như bạn đã cập nhật câu hỏi của mình và bây giờ bạn không cần bù đắp mảng, nhưng bù đắp chỉ mục để giải pháp @sawa sẽ hoạt động tốt cho bạn


1

Ariel nói đúng. Đây là cách tốt nhất để giải quyết vấn đề này và nó không tệ lắm

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

Điều đó hoàn toàn có thể chấp nhận được, và tốt hơn hầu hết các giải pháp mà tôi đã thấy cho việc này. Tôi luôn nghĩ đây là những gì #inject dành cho ... ôi thôi.


1

Một cách tiếp cận khác là sử dụng 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

Điều này hoạt động trong mọi phiên bản ruby:

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

Và đối với một mảng chung:

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

thiếu một dấu ngoặc trong ví dụ thứ hai.
waferthin

0
offset = 2
some_array[offset..-1].each_with_index{|item, index| some_func(item, index+offset) }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.