2012-06-08 54 views
5

Nói rằng tôi có một băm như:Sắp xếp băm theo chiều dài của giá trị chứa

foo = { 
    :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array 
    :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array, 
    :blah => ['at'] # has a total str length of 2 characters inside of the array 
    # etc... 
} 

Làm thế nào tôi sẽ đi về sắp xếp băm này với tổng chiều dài chuỗi các mặt hàng chứa bên trong mảng? Kết quả là trật tự băm trong trường hợp này sẽ là: :blah, :bar, :baz

+1

Bạn có ý nghĩa gì khi "sắp xếp băm"? – nonowarn

+2

Hãy tưởng tượng Ruby thứ hai không thể giúp bạn. Bạn sẽ làm gì sau đó? – alf

+0

@alf Tôi đoán tôi sẽ là SOL ... nhưng làm thế nào để chỉ ra rằng giúp tôi? –

Trả lời

11

Tôi chỉ muốn làm điều này:

Hash[foo.sort_by { |k, v| v.join.length }] 

tôi giả sử bạn đang không có ý định thay đổi các giá trị Hash gốc, chỉ cần tái sắp xếp chúng.

1
foo.sort_by { |_,v| v.reduce(:+).size } 
+0

Ngay cả 'giảm ​​(: +)' là đủ. Tuy nhiên, loại này theo chuỗi (theo thứ tự chữ cái), không phải theo độ dài chuỗi. – Casper

+0

@ Làm tốt bạn đúng. Tôi đã chỉnh sửa câu trả lời để sử dụng độ dài chuỗi. –

3

Theo truyền thống, băm không ra lệnh, và do đó không sắp xếp. Ruby 1,9 hashes được đặt hàng, nhưng ngôn ngữ cung cấp không có cách dễ dàng để sắp xếp lại các yếu tố. Cũng giống như trong 1.8, phân loại một hash trả về một mảng các cặp: (. Trên thực tế, 1,8 sẽ thổi lên trên đó vì những biểu tượng không thể so sánh được trong 1.8, nhưng không bao giờ quan tâm)

{ c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ] 

Nhưng khi miễn là bạn đang OK với danh sách các cặp, bạn có thể sắp xếp một băm (hoặc một mảng) bởi bất cứ điều gì bạn thích. Chỉ cần sử dụng sort_by và vượt qua một khối để trích ra phần chủ chốt sắp xếp, hoặc sử dụng các loại với một khối mà không so sánh:

foo.sort_by { |key, strings| strings.join.length } 

hoặc, nếu bạn muốn những cái dài nhất đầu tiên:

foo.sort_by { |key, strings| -strings.join.length } 

Sau đó, nếu bạn đang sử dụng 1.9 và muốn bật kết quả trở thành một Hash, bạn có thể làm như vậy do đó (nhờ, Jörg W Mittag):

Hash[ foo.sort_by { |key, strings| strings.join.length } ] 

... đó là câu trả lời tương tự như d11wtq.

+0

'Hash :: []' lấy chính xác loại mảng khóa-giá trị mà tất cả các phương thức 'Hash' khác tạo ra, vì vậy, nếu bạn muốn' map' hoặc 'sort' hoặc' sort_by' là 'Hash', bạn chỉ cần quấn toàn bộ biểu thức trong 'Hash […]' để lấy lại một 'Hash'. –

1

Hash không đảm bảo thứ tự các khóa trong khái niệm của nó. Nhưng trong Ruby 1.9, Hash's key order is saved. Vì vậy, bạn có thể sử dụng mã trong câu trả lời khác nếu bạn sử dụng 1,9.

Nhưng tôi không muốn khuyên bạn nên dựa vào hành vi này vì đó là hành vi tiềm ẩn và tôi sợ những thay đổi trong tương lai. Thay vào đó, sử dụng phương thức sinh ra mục nhập băm theo thứ tự tổng của độ dài của chuỗi.

def each_by_length(hash) 
    hash = hash.sort_by { |_, strs| strs.map(&:length).inject(0, &:+) } 
    hash.each do |k, v| 
    yield k, v 
    end 
end 
Các vấn đề liên quan