ruby string to hash conversion
14,766
Solution 1
Direct copy/past of an IRB session:
>> str.split(/, /).inject(Hash.new{|h,k|h[k]=[]}) do |h, s|
.. v,k = s.split(/@/)
.. h[k] << v
.. h
.. end
=> {"p"=>["uu"], "m"=>["xx", "zz"], "n"=>["yy"]}
Solution 2
Simpler code for a newbie :)
str = "uu@p, xx@m, yy@n, zz@m"
h = {}
str.split(",").each do |x|
v,k = x.split('@')
h[k] ||= []
h[k].push(v)
end
p h
Solution 3
FP style:
grouped = str.split(", ").group_by { |s| s.split("@")[1] }
Hash[grouped.map { |d, emails| [d, emails.map { |s| s.split("@")[0] }] }]
#=> {"m"=>["xx", "zz"], "n"=>["yy"], "p"=>["uu"]}
As usual, the solution is much shorter and clearer if you resort to Facets cool abstractions (no need to install the whole library, just copy the specific methods to your extensions module):
require 'facets'
str.split(", ").map_by { |s| s.split("@", 2).reverse }
#=> {"m"=>["xx", "zz"], "n"=>["yy"], "p"=>["uu"]}
Facets#map_by
= group_by
+map
Author by
Mr. Black
profile for Mr. Black on Stack Exchange, a network of free, community-driven Q&A sites http://stackexchange.com/users/flair/177944.png
Updated on June 28, 2022Comments
-
Mr. Black almost 2 years
I have a string like this,
str = "uu@p, xx@m, yy@n, zz@m"
I want to know how to convert the given string into a hash. (i.e my actual requirement is, how many values (before the @ symbol) have the m, n and p. I don't want the counting, I need an exact value). The output would be better like this,
{"m" => ["xx", "zz"], "n" => ["yy"], "p" => ["uu"]}
Can help me anyone, please?
-
Mr. Black over 12 yearsMany thanks @Michael. This is what i expect. Again, I'm exciting about the power of inject method. Can, you please explain this portion "..inject(Hash.new{|h,k|h[k]=[]}).."? It's help to improve myself.
-
Michael Kohl over 12 yearsGlad to help! :-) If your question is sufficiently answered, please accept it so other people know.
-
Michael Kohl over 12 yearsSure, I'm using the block form of
Hash.new
(see docs) to inject a hash that has the empty array as default value. -
Michael Kohl over 12 yearsAren't folds (and hence
inject
) functional enough for you? ;-) -
d11wtq over 12 yearsI think I prefer this for no other reason than the fact it does not involve keeping state in temporary variables.
-
tokland over 12 years@Michael. Let's call it then "another FP-style answer". However, note that "h[k] << v" is hardly functional :-p Moreover, a typical FP advice is: don't resort to folds when there are other abstractions at hand (since we potentially can write almost all enumerable abstractions with folds: map/select/group_by/partition/max/min/...).
-
Michael Kohl over 12 yearsFair enough about mutating the array. About that piece of advice you mention: I never really heard that one before and I do Haskell and Clojure on a fairly regular basis. :-) Anyway, I like your answer, I was one of the 2 upvoters.
-
tokland over 12 years@Michael. To be fair, in this case vanilla Ruby has no suitable abstraction (my first snippet splits twice, which is conceptually ugly). So, I'd go for either your inject or Facets#map_by.