2010-06-15 37 views
40

Có cách nào để làm phẳng một băm thành một chuỗi, với các dấu phân cách tùy chọn giữa các khóa và giá trị, và các cặp khóa/giá trị không?Làm phẳng băm thành chuỗi trong Ruby

Ví dụ, print {:a => :b, :c => :d}.flatten('=','&') nên in a=b&c=d

tôi đã viết một số mã để làm điều này, nhưng tôi đã tự hỏi nếu có một cách gọn gàng:

class Hash 
    def flatten(keyvaldelimiter, entrydelimiter) 
    string = "" 
    self.each do 
     |key, value| 
     key = "#{entrydelimiter}#{key}" if string != "" #nasty hack 
     string += "#{key}#{keyvaldelimiter}#{value}" 
    end 
    return string 
    end 
end 

print {:a => :b, :c => :d}.flatten('=','&') #=> 'c=d&a=b' 

Cảm ơn

Trả lời

92

tôi sẽ không ghi đè .flatten , đã được xác định:

Trả lại mảng mới là làm phẳng một chiều này băm. Tức là, đối với mỗi khóa hoặc giá trị là một mảng, hãy trích xuất các phần tử của nó vào mảng mới. Không giống như Mảng # làm phẳng, phương pháp này không làm phẳng đệ quy theo mặc định. Nếu đối số cấp độ tùy chọn xác định mức độ tham gia để làm phẳng.

Đây là cách đơn giản nhất để làm điều đó mà tôi biết:

{:a => 100, :b => 200}.map{|k,v| "#{k}=#{v}"}.join('&') 
# => "a=100&b=200"
+5

Bạn có thể đơn giản hóa việc này hơn nữa. Xem câu trả lời của tôi để biết chi tiết. Gist sẽ thay thế '| k, v |' bằng '| e |' làm cho 'e' thành mảng mà bạn có thể gọi là' e.join ('=') '. –

+1

làm thế nào để làm ngược lại để có được một băm – jenuine

4

Vâng, bạn có thể làm điều đó với các phương pháp và mảng chuẩn:

class Hash 
    def flatten(keyvaldelimiter, entrydelimiter) 
    self.map { |k, v| "#{k}#{keyvaldelimiter}#{v}" }.join(entrydelimiter) 
    end 
end 

Bạn cũng có thể quan tâm đến số Rails to_query method.

Ngoài ra, rõ ràng, bạn có thể viết "#{k}#{keyvaldelimiter}#{v}" như k.to_s + keyvaldelimiter + v.to_s ...

+2

Hoặc '[k, v] .join (keyvaldelimiter)'. – henrikhodne

1

Không chắc chắn nếu có một cách tích hợp, nhưng đây là một số mã ngắn hơn:

class Hash 
    def flatten(kvdelim='', entrydelim='') 
    self.inject([]) { |a, b| a << b.join(kvdelim) }.join(entrydelim) 
    end 
end 

puts ({ :a => :b, :c => :d }).flatten('=', '&') # => a=b&c=d 
21

biến thể nhẹ của @ elektronaut của phiên bản:

Bạn thực sự có thể đặt vừa một |e| có thay vì |k, v| trong trường hợp nào e là một mảng gồm hai phần tử và bạn có thể gọi e.join('='). Nhìn chung, bạn có một cái gì đó giống như

class Hash 
    def join(keyvaldelim=$,, entrydelim=$,) # $, is the global default delimiter 
    map {|e| e.join(keyvaldelim) }.join(entrydelim) 
    end 
end 

{a: 100, b: 200}.join('=', '&') # I love showing off the new Ruby 1.9 Hash syntax 
# => 'a=100&b=200' 
+5

Tôi sẽ nghiêm túc đặt câu hỏi như thế nào thông minh nó là để khỉ vá 'Hash', đặc biệt là với một tên không có tên là phương thức' join'. Trong khi tôi mong đợi điều này từ nhiều người, tôi rất ngạc nhiên khi thấy gợi ý đó từ một người có kinh nghiệm. – akostadinov

0

Điều gì về việc nhận được nó ở định dạng JSON. Bằng cách đó, định dạng rõ ràng.

Có rất nhiều công cụ JSON cho ruby. Tuy nhiên, chưa bao giờ thử chúng. Nhưng đầu ra sau đó tất nhiên sẽ trượt vào javascript, vv dễ dàng hơn. Có khả năng một dòng.

Khoản tiết kiệm lớn, mặc dù sẽ có trong tài liệu, vì vậy bạn sẽ cần ít hơn nhiều.

4

Nếu bạn đang cố gắng tạo chuỗi truy vấn url, bạn chắc chắn nhất nên sử dụng phương thức như toes_param của activesupport (được đặt bí danh là to_query). Hãy tưởng tượng các vấn đề nếu bạn có dấu và hoặc dấu bằng trong chính dữ liệu.

to_query chăm sóc thoát:

>> require 'active_support/core_ext/object' 
>> {'a&' => 'b', 'c' => 'd'}.to_query 
>> => "a%26=b&c=d" 

EDIT

@fahadsadah làm cho một điểm tốt về việc không muốn tải Rails. Ngay cả đối tượng active_support/core_ext/cũng sẽ tải 71 tệp. Nó cũng là các lớp lõi của khỉ.

Một giải pháp trọng lượng nhẹ và gọn gàng hơn:

require 'rack' # only loads 3 files 
{'a&' => 'b', 'c' => 'd'}.map{|pair| 
    pair.map{|e| Rack::Utils.escape(e.to_s) }.join('=') 
}.join('&') 
# => "a%26=b&c=d" 

Điều quan trọng là để thoát khỏi, nếu không hoạt động là không thể đảo ngược.

+0

Đó là tất cả rất tốt, và đó là một điểm tốt, nhưng tôi không muốn yêu cầu Rails được cài đặt khi tôi tạo ra các băm nguồn –

+0

Rails cho chiến thắng !! –

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