2012-07-03 37 views
10

Python có một tính năng tuyệt vời:Ruby có một cái gì đó giống như sự hiểu biết danh sách của Python?

print([j**2 for j in [2, 3, 4, 5]]) # => [4, 9, 16, 25] 

Trong Ruby nó thậm chí còn đơn giản hơn:

puts [2, 3, 4, 5].map{|j| j**2} 

nhưng nếu nó về lồng vòng Python trông thuận tiện hơn.

Trong Python chúng ta có thể làm điều này:

digits = [1, 2, 3] 
chars = ['a', 'b', 'c']  
print([str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a'])  
# => ['2a', '3a'] 

Tương đương trong Ruby là:

digits = [1, 2, 3] 
chars = ['a', 'b', 'c'] 
list = [] 
digits.each do |d| 
    chars.each do |ch| 
     list.push d.to_s << ch if d >= 2 && ch == 'a' 
    end 
end 
puts list 

Liệu Ruby có một cái gì đó tương tự?

+3

Điều gì đó tương tự được thảo luận tại đây: http://stackoverflow.com/questions/310426/list-comprehension-in-ruby – Bharat

+2

Phiên bản ngắn gọn là Ruby có một vài thứ khác nhau tương tự nhau, nhưng không có gì chính xác giống nhau và không có gì là súc tích (hoặc có thể đọc được). Phiên bản dài… là câu trả lời của RBK. – abarnert

+1

@RBK cũng có, nhưng nó không phải về vòng lặp lồng nhau (1+ mảng) – defhlt

Trả lời

11

Cách phổ biến trong Ruby là kết hợp đúng cách EnumerableArray phương pháp để đạt được như vậy:

digits.product(chars).select{ |d, ch| d >= 2 && ch == 'a' }.map(&:join) 

Đây là chỉ có 4 hoặc lâu hơn nhân vật dài hơn danh sách các hiểu biết và cũng giống như biểu cảm (IMHO tất nhiên, nhưng vì việc hiểu danh sách chỉ là một ứng dụng đặc biệt của danh sách đơn lẻ, người ta có thể cho rằng có thể xây dựng lại đầy đủ bằng cách sử dụng các phương thức thu thập của Ruby), trong khi không cần bất kỳ cú pháp đặc biệt nào.

1

Theo đề xuất của RBK ở trên, List comprehension in Ruby cung cấp toàn bộ hàng loạt các cách khác nhau để thực hiện những việc như sắp xếp danh sách trong Ruby.

Không ai mô tả rõ ràng vòng lặp lồng nhau, nhưng ít nhất một số trong số chúng có thể lồng nhau khá dễ dàng.

Ví dụ: câu trả lời được chấp nhận bởi Robert Gamble đề xuất thêm phương thứC# comprehray.

class Array 
    def comprehend(&block) 
    return self if block.nil? 
    self.collect(&block).compact 
    end 
end 

Sau khi làm điều đó, bạn có thể viết mã của bạn như:

digits.comprehend{|d| chars.comprehend{|ch| d.to_s+ch if ch =='a'} if d>=2} 

So sánh với mã Python:

[str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a'] 

Sự khác biệt là khá nhỏ:

  1. Mã Ruby dài hơn một chút. Nhưng đó chỉ là một thực tế là "hiểu" được viết ra; bạn luôn có thể gọi nó là cái gì đó ngắn hơn nếu bạn muốn.
  2. Mã Ruby đặt mọi thứ theo thứ tự khác nhau — các mảng đến lúc bắt đầu thay vì ở giữa. Nhưng nếu bạn nghĩ về nó, đó là chính xác những gì bạn mong đợi, và muốn, vì triết lý "mọi thứ là một phương pháp".
  3. Mã Ruby yêu cầu niềng răng lồng nhau cho lồng ghép lồng nhau. Tôi không thể nghĩ ra một cách rõ ràng xung quanh điều này mà không làm cho mọi việc tồi tệ hơn (bạn không muốn gọi "[str, chữ số] .comprehend2" hoặc bất cứ điều gì ...).

Tất nhiên sức mạnh thực sự của Python ở đây là nếu bạn quyết định muốn đánh giá danh sách một cách lười biếng, bạn có thể chuyển đổi hiểu thành biểu thức máy phát chỉ bằng cách xóa dấu ngoặc đơn (hoặc biến chúng thành dấu ngoặc đơn, tùy thuộc vào bối cảnh). Nhưng ngay cả ở đó, bạn có thể tạo ra một Array # lazycomprehend hoặc một cái gì đó.

2

Như bạn biết Ruby không có cú pháp cú pháp cho danh sách hiểu, vì vậy bạn càng có thể nhận được gần bằng cách sử dụng các khối theo cách giàu trí tưởng tượng.Người ta đã đề xuất ý tưởng khác nhau, hãy nhìn vào lazylistverstehen cách tiếp cận, cả hai đều hỗ trợ lồng comprehensions với điều kiện:

require 'lazylist' 
list { [x, y] }.where(:x => [1, 2], :y => [3, 4]) { x+y>4 }.to_a 
#=> [[1, 4], [2, 3], [2, 4]] 

require 'verstehen' 
list { [x, y] }.for(:x).in { [1, 2] }.for(:y).in { [3, 4] }.if { x+y>4 }.comprehend 
#=> [[1, 4], [2, 3], [2, 4]] 

Tất nhiên đó không phải những gì bạn muốn gọi thành ngữ Ruby, vì vậy nó thường là an toàn hơn để sử dụng điển hình product + select + map cách tiếp cận.

Các vấn đề liên quan