3

I have some key-value pair strings in an array:

array = [ "Name = abc", "Id = 123", "Interest = Rock Climbing" ]

I need to convert it to a hash:

hash = { "Name" => "abc", "Id" => "123", "Interest" => "Rock Climbing" }

I must be doing something wrong because I'm getting weird mappings with my .shift.split resulting in {"Name=abc"=>"Id=123"}.

4 Answers 4

7

All you need to do is split each part of the array into a key and value (yielding an array of two-element arrays) and then pass the result to the handy Hash[] method:

arr = [ "Name = abc", "Id = 123", "Interest = Rock Climbing" ]

keys_values = arr.map {|item| item.split /\s*=\s*/ }
# => [ [ "Name", "abc" ],
#      [ "Id", "123" ],
#      [ "Interest", "Rock Climbing" ] ]

hsh = Hash[keys_values]
# => { "Name" => "abc",
#      "Id" => "123",
#      "Interest" => "Rock Climbing" }
Sign up to request clarification or add additional context in comments.

3 Comments

I tried with your above code, and it gives me below error wrong array length at 20 (expected 2, was 3) Can anyone help me with resolving this. Also this same code is only not working for me in some rare case, however I don't see the difference in values for both working and not working cases.
@VinitSharma The Hash[] method expects data in pairs, i.e. an Array of Arrays of two elements each, like [[key1, val1], [key2, val2], ...]. The error is telling you that one of those Arrays has three elements instead of two.
Yes you are right, my source string was getting created incorrectly because of a single space with more than two elements. Got removed the white space and its working now. Thanks for the help!
2

You can do it this way (using Enumerable#each_with_object):

array.each_with_object({}) do |a, hash|
    key,value = a.split(/\s*=\s*/) # splitting the array items into key and value
    hash[key] = value    # storing key => value pairs in the hash
end
# => {"Name"=>"abc", "Id"=>"123", "Interest"=>"Rock Climbing"}

If you find it little difficult to understand the each_with_object, you can do it in a naive way (Just accumulating the key and values in the result_hash):

result_hash = {}
array.each do |a|
    key,value = a.split(/\s*=\s*/) # splitting the array items into key and value
    result_hash[key] = value # storing key => value pairs in the result_hash
end
result_hash
# => {"Name"=>"abc", "Id"=>"123", "Interest"=>"Rock Climbing"}

Comments

1

Try this

array.map {|s| s.split('=')}.to_h

=> {"Name "=>" abc", "Id "=>" 123", "Interest "=>" Rock Climbing"} 

Comments

0
array.each_with_object({}) { |s,h| h.update([s.split(/\s*=\s*/)].to_h) }
  #=> {"Name"=>"abc", "Id"=>"123", "Interest"=>"Rock Climbing"} 

For Ruby versions prior to 2.0 (when Array#to_h was introduced) replace [s.split(/\s*=\s*/)].h with Hash[[s.split(/\s*=\s*/)]]. The steps:

enum = array.each_with_object({})
  #=> #<Enumerator: ["Name = abc", "Id = 123",
  #     "Interest = Rock Climbing"]:each_with_object({})>

We can see the elements of this enumerator by converting it to an array:

enum.to_a
  #=> [["Name = abc", {}], ["Id = 123", {}], ["Interest = Rock Climbing", {}]] 

The first element of enum is passed to the block, the block variables are assigned:

s,h = enum.next
  #=> ["Name = abc", {}] 
s #=> "Name = abc" 
h #=> {} 

and the block calculation is performed:

h.update([s.split(/\s*=\s*/)].to_h)
  #=> h.update([["Name", "abc"]].to_h) 
  #   {}.update({"Name"=>"abc"})
  #   {"Name"=>"abc"}

which is the updated value of h.

The next element of enum passed to the block is:

s,h = enum.next
  #=> ["Id = 123", {"Name"=>"abc"}] 
s #=> "Id = 123" 
h #=> {"Name"=>"abc"} 

h.update([s.split(/\s*=\s*/)].to_h)
  #=> {"Name"=>"abc", "Id"=>"123"}

and so on.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.