2017-01-21 21 views
5

#each_with_object#inject cả hai có thể được sử dụng để tạo băm.Tại sao #each_with_object và #inject chuyển thứ tự tham số khối?

Ví dụ:

matrix = [['foo', 'bar'], ['cat', 'dog']] 

some_hash = matrix.inject({}) do |memo, arr| 
    memo[arr[0]] = arr 
    memo # no implicit conversion of String into Integer (TypeError) if commented out 
end 
p some_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]} 

another_hash = matrix.each_with_object({}) do |arr, memo| 
    memo[arr[0]] = arr 
end 
p another_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]} 

Một trong những khác biệt chính giữa hai là #each_with_object theo dõi memo qua toàn bộ lặp trong khi #inject bộ memo bằng giá trị được trả về bởi các khối trên mỗi lần lặp.

Sự khác biệt khác là thứ tự hoặc tham số khối.

Có một số ý định được truyền đạt ở đây không? Nó không có ý nghĩa để đảo ngược các tham số khối của hai phương pháp tương tự.

Trả lời

4

Chúng có tổ tiên khác nhau.

  • each_with_object đã được thêm vào của Ruby 1,9 năm 2007
  • inject đi trở lại Smalltalk trong 1980

Tôi đoán nếu ngôn ngữ được thiết kế với cả hai phương pháp từ bắt đầu họ có thể mong chờ lập luận trong cùng một thứ tự. Nhưng đây không phải là cách nó xảy ra. inject đã bắt đầu từ khi bắt đầu Ruby trong khi each_with_object chỉ được thêm 10 năm sau đó.

inject hy vọng đối số theo thứ tự giống như Smalltalk của inject:into:

collection inject: 0 into: [ :memo :each | memo + each ] 

mà không một lần trái. Bạn có thể nghĩ bộ sưu tập như một dải giấy dài được gấp lại từ bên trái và cửa sổ trượt của chức năng gấp luôn là phần đã được gấp lại cùng với phần tử tiếp theo của dải giấy còn lại

# (memo = 0 and 1), 2, 3, 4 
# (memo = 1 and 2), 3, 4     
# (memo = 3 and 3), 4      
# (memo = 6 and 4)      

Theo quy ước Smalltalk có ý nghĩa trở lại sau đó vì tất cả các phương pháp ban đầu trong Enumerable được lấy từ Smalltalk và Matz không muốn gây nhầm lẫn cho những người đã quen thuộc với Smalltalk.

Cũng không ai có thể biết trước điều đó sẽ xảy ra trong năm 2007 khi each_with_object được giới thiệu với Ruby 1.9 và thứ tự đối số phản ánh thứ tự từ vựng của tên phương thức, là each ... object.

Và do đó hai phương thức này mong đợi các đối số trong các đơn đặt hàng khác nhau vì lý do lịch sử.

+0

Tài khoản tốt và thú vị. Tôi hy vọng cũng có một mong muốn nhất quán với [Enumerator # with_object] (http://ruby-doc.org/core-2.3.0/Enumerator.html#method-i-with_object). Ví dụ. 'arr.each_with_index.with_object ({}) {| (e, i), h | ...'. Có các biến khối '| h, (e, i) |' sẽ vô cùng khó hiểu. –

+0

Tính nhất quán (trong vị trí của các biến khối) với [Enumerable # each_with_index] (http://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-each_with_index) và [Enumerator # each_index] (http://ruby-doc.org/core-2.3.0/Enumerable.html#method-i-each_with_index) cũng có thể là một yếu tố. –

+1

"thứ tự của đối số phản ánh thứ tự từ vựng của tên phương thức, đó là' mỗi ... đối tượng'. "........... Tôi luôn quên thứ tự, bây giờ tôi sẽ không bao giờ. –

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