Existe-t-il un moyen d'aplatir un hachage en une chaîne, avec des délimiteurs facultatifs entre les clés et les valeurs, et des paires clé/valeur?
Par exemple, print {:a => :b, :c => :d}.flatten('=','&')
devrait imprimer a=b&c=d
J'ai écrit du code pour le faire, mais je me demandais s'il y avait une façon plus nette:
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'
Merci
Je ne remplacerais pas .flatten
, qui est déjà défini:
Renvoie un nouveau tableau qui est un aplatissement unidimensionnel de ce hachage. Autrement dit, pour chaque clé ou valeur qui est un tableau, extrayez ses éléments dans le nouveau tableau. Contrairement à Array # flatten, cette méthode ne s'aplatit pas récursivement par défaut. Si l'argument de niveau facultatif détermine le niveau de récursivité à aplatir.
C'est la façon la plus simple de le faire que je connaisse:
{:a => 100, :b => 200}.map{|k,v| "#{k}=#{v}"}.join('&')
# => "a=100&b=200"
Légère variation de la version @ elektronaut:
Vous pouvez réellement y mettre juste un |e|
Au lieu de |k, v|
Auquel cas e
est un tableau de deux éléments et vous pouvez appeler e.join('=')
. Au total, vous avez quelque chose comme
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'
Eh bien, vous pouvez le faire avec des méthodes et des tableaux standard:
class Hash
def flatten(keyvaldelimiter, entrydelimiter)
self.map { |k, v| "#{k}#{keyvaldelimiter}#{v}" }.join(entrydelimiter)
end
end
Vous pourriez également être intéressé par les Rails to_query
méthode .
De plus, évidemment, vous pouvez écrire "#{k}#{keyvaldelimiter}#{v}"
comme k.to_s + keyvaldelimiter + v.to_s
...
Si vous essayez de générer une chaîne de requête d'URL, vous devez très certainement utiliser une méthode comme to_param d'actifsupport (alias to to_query). Imaginez les problèmes si vous aviez une esperluette ou un signe égal dans les données elles-mêmes.
to_query prend soin de s'échapper:
>> require 'active_support/core_ext/object'
>> {'a&' => 'b', 'c' => 'd'}.to_query
>> => "a%26=b&c=d"
MODIFIER
@fahadsadah fait un bon point sur le fait de ne pas vouloir charger Rails. Même active_support/core_ext/object chargera 71 fichiers. Il classe également les classes principales de patches de singe.
Une solution légère et plus propre:
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"
Il est important de s'échapper, sinon l'opération n'est pas réversible.
Je ne sais pas s'il existe une méthode intégrée, mais voici un code plus court:
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
Qu'en est-il de l'obtenir au format JSON. De cette façon, le format est clair.
Il existe de nombreux outils JSON pour Ruby. Mais je ne les ai jamais essayés. Mais la sortie glissera alors bien sûr en javascript, etc. plus facilement. Probablement une ligne.
Les grosses économies, cependant, seraient dans la documentation, car vous en aurez besoin de beaucoup moins.