Spłaszczanie hasha na string w Ruby

Czy istnieje sposób na spłaszczenie hasha w łańcuch z opcjonalnymi ogranicznikami między kluczami i wartościami oraz parami klucz/wartość?

Na przykład, print {:a => :b, :c => :d}.flatten('=','&') powinien wydrukować a=b&c=d

Napisałem jakiś kod, aby to zrobić, ale zastanawiałem się, czy nie ma lepszego sposobu:

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'

Dzięki

 44
Author: Fahad Sadah, 2010-06-15

6 answers

Nie nadpisałbym .flatten, który jest już zdefiniowany:

Zwraca nową tablicę, która jest jednowymiarowe spłaszczenie tego hash. Oznacza to, że dla każdego klucza lub wartości to jest tablica, wyodrębnij jej elementy do nowej tablicy. W przeciwieństwie do Array#flatten, ta metoda nie domyślnie spłaszcz rekurencyjnie. Jeśli opcjonalny argument poziomu określa poziom rekurencji do spłaszczenia.

Jest to najprostszy sposób, który znam:

{:a => 100, :b => 200}.map{|k,v| "#{k}=#{v}"}.join('&')
# => "a=100&b=200"
 99
Author: elektronaut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 16:33:01

Mała zmiana wersji @elektronauta:

Możesz umieścić tam tylko |e| zamiast |k, v| w takim przypadku e jest tablicą dwóch elementów i możesz wywołać e.join('='). W sumie masz coś w stylu

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'
 22
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 18:31:00

Cóż, można to zrobić standardowymi metodami i tablicami:

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

Być może zainteresuje cię również metoda Rails to_query .

Również, oczywiście, można zapisać "#{k}#{keyvaldelimiter}#{v}" jako k.to_s + keyvaldelimiter + v.to_s...

 5
Author: Amadan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 16:27:17

Jeśli próbujesz wygenerować ciąg zapytania url, z pewnością powinieneś użyć metody takiej jak to_param activesupport (aliased to to_query). Wyobraź sobie problemy, jeśli masz Znak ampersand lub equal w samych danych.

To_query dba o ucieczkę:

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

EDIT

@fahadsadah ma rację, że nie chce ładować szyn. Nawet active_support / core_ext / object załaduje 71 plików. Posiada również podstawowe klasy.

Lekki i roztwór czyszczący:

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"

To ważne, aby uciec, inaczej operacja nie jest odwracalna.

 4
Author: Kelvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-24 22:58:21

Nie wiem, czy jest wbudowany sposób, ale tu jest jakiś krótszy kod:

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
 1
Author: henrikhodne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 16:27:33

A co z zapisaniem go w formacie JSON? W ten sposób format jest jasny.

Istnieje wiele narzędzi JSON dla Rubiego. Nigdy ich nie próbowałem. Ale wyjście będzie oczywiście przesuwać do javascript, itp łatwiejsze. Prawdopodobnie jedna linijka.

Duże oszczędności, choć byłoby w dokumentacji, w tym trzeba znacznie mniej.

 0
Author: Tom Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 20:24:07