What is the most elegant way to break the following array
["name:alex", "age:14"]
into the following hash:
{:name=>"alex", :age=>"14"}
In Ruby 2.1 arrays ship with the to_h method
p ["name:alex", "age:14"].map{|el| el.split(":")}.to_h #=>{"name"=>"alex", "age"=>"14"}
With symbols as keys:
["name:alex", "age:14"].map{|el| k,v = el.split(":"); [k.to_sym, v]}.to_h
You need to split each pair, and convert the results to a hash with Hash[]:
array = ["name:alex", "age:14"]
Hash[array.map { |s| s.split(':') }]
# => {"name"=>"alex", "age"=>"14"}
This takes advantage of Ruby's convention for freely converting between arrays and hashes. Given an array [[a, b], [c, d]], each element is considered to be a [key, value] pair. You only need to turn your array from ["name:alex", "age:14"] into [['name', 'alex'], ['age', '14']] and Hash[] will do the rest. Conversly, you can call .to_a on a Hash and produce the an array containing [[key1, value1], [key2, value2], ...].
If you want the keys to be symbols, you can add that to the map:
Hash[array.map { |s| pair = s.split(':'); [pair.first.to_sym, pair.last] }]
One more way to go :
a = ["name:alex", "age:14"]
hsh = a.each_with_object({}) do |s,h|
k,v = s.split(":")
h[k.to_sym] = v
end
hsh # => {:name=>"alex", :age=>"14"}
Just another way using Enumerable#reduce
array = ["name:alex", "age:14"]
array.reduce({}) { |a, e| k, v = e.split(':'); a.merge({k.to_sym => v}) }
# => {:name=>"alex", :age=>"14"}
Try this
arr = ["name:alex", "age:14"]
arr.group_by{|str| str.split(":")}.keys.each_with_object({}){|ele, h|
h[ele.first.to_sym] = ele.last}
# => {:name=>"alex", :age=>"14"}
I would use tap and scan, and no semicolon.
a = ["name:alex", "age:14"]
{}.tap { |h| a.each{ |e| e.scan(/(\w+):(\w+)/) { |k, v| h[k.to_sym] = v } } }
# => {:name=>"alex", :age=>"14"}
Related
I have an array:
arr = [a, ab, abc]
I want to make a hash, using the values of the array as the keys:
newhash = [a[1], ab[1], abc[1]]
I have tried:
arr.each do |r|
newhash[r] == 1
end
to no avail.
How would I about accomplishing this in ruby?
If you are feeling like a one-liner, this will work as well
h = Hash[arr.collect { |v| [v, 1] } ]
collect is invoked once per element in the array, so it returns an array of 2-element arrays of key-value pairs.
Then this is fed to the hash constructor, which turns the array of pairs into a hash
You could also use the #reduce method from Enumerable (which is included into the Array class).
new_hash = arr.reduce({}) { |hsh, elem| hsh[elem] = 1; hsh }
And your new_hash looks like this in Ruby:
{"a": 1, "ab": 1, "abc": 1}
== is comparison. = is assigning. So just modify == into =. It works.
newhash = {}
arr.each do |r|
newhash[r] = 1
end
(I believe a, ab, abc are strings)
To learn more, this might help you. Array to Hash Ruby
You can do it like this:
ary = [[:foo, 1], [:bar, 2]]
Hash[ary] # => {:foo=>1, :bar=>2}
If you want to do it like you tried earlier, you want to initialize hash correctly:
ary = [:foo, :bar]
hash = {}
ary.each do |key|
hash[key] = 1
end # => {:foo=>1, :bar=>2}
I have a hash:
input = {"a"=>"440", "b"=>"-195", "c"=>"-163", "d"=>"100"}
From it I want to get two hashes, one containing the pairs whose value (as integer) is positive, the other containing negative values, for example:
positive = {"a"=>"440", "d"=>"100" }
negative = {"b"=>"-195", "c"=>"-163" }
How can I achieve this using the minimum amount of code?
You can use the Enumerable#partition method to split an enumerable object (like a hash) based on a condition. For example, to separate positive/negative values:
input.partition { |_, v| v.to_i < 0 }
# => [[["b", "-195"], ["c", "-163"]],
# [["a", "440"], ["d", "100"]]]
Then, to get the desired result, you can use map and to_h to convert the key/value arrays to hashes:
negative, positive = input.partition { |_, v| v.to_i < 0 }.map(&:to_h)
positive
# => {"a"=>"440", "d"=>"100"}
negative
# => {"b"=>"-195", "c"=>"-163"}
If you use a version of Ruby prior 2.1 you can replace the Array#to_h method (that was introduced in Ruby 2.1) like this:
evens, odds = input.partition { |_, v| v.to_i.even? }
.map { |alist| Hash[alist] }
This implementation uses Enumerable#group_by:
input = {"a"=>"440", "b"=>"-195", "c"=>"-163", "d"=>"100"}
grouped = input.group_by { |_, v| v.to_i >= 0 }.map { |k, v| [k, v.to_h] }.to_h
positives, negatives = grouped.values
positives #=> {"a"=>"440", "d"=>"100"}
negatives #=> {"b"=>"-195", "c"=>"-163"}
I must say that Enumerable#partition is more appropriate, as #toro2k answered.
something like this then?
positive = Hash.new
negative = Hash.new
input.each_pair { |var,val|
if val.to_i > 0
positive[var] = val
else
negative[var] = val
end
}
Given a hash of key/value pairs, how can I turn that into an array of individual hashes for each key/value pair.
So for example, starting with:
{"hello"=>"bonjour", "goodbye"=>"au revoir"}
And turning that into:
[ {"hello" => "bonjour"}, {"goodbye" => "au revoir"} ]
I got that with the following but am wondering if there's an easier approach:
array = []
hash.each do |k,v|
h = Hash.new
h[k] = v
array << h
end
Do as below using Enumerable#map:
h = {"hello"=>"bonjour", "goodbye"=>"au revoir"}
h.map { |k,v| { k => v } }
# => [{"hello"=>"bonjour"}, {"goodbye"=>"au revoir"}]
I would like to extract hash key values to an array when a condition is met. For example, with hash h I want to extract the keys where the values are "true":
h = { :a => true, :b => false, :c =>true }
I've come up with this:
h.map {|k,v| k if v==true} - [nil]
Any alternatives?
h.select { |_, v| v }.keys
Will do the same, but in more readable way.
You can also do
s = {}
h.each do |k,v|
s[k] = v if v==true
end
In some scenario of Ruby 1.8. If I have a hash
# k is name, v is order
foo = { "Jim" => 1, "bar" => 1, "joe" => 2}
sorted_by_values = foo.sort {|a, b| a[1] <==> b[1]}
#sorted_by_values is an array of array, it's no longer a hash!
sorted_by_values.keys.join ','
my workaround is to make method to_hash for Array class.
class Array
def to_hash(&block)
Hash[*self.collect { |k, v|
[k, v]
}.flatten]
end
end
I can then do the following:
sorted_by_values.to_hash.keys.join ','
Is there a better way to do this?
Hashes are unordered by definition. There can be no such thing as a sorted Hash. Your best bet is probably to extract the keys from the sorted array using collect and then do a join on the result
sortedByValues = foo.sort {|a, b| a[1] <==> b[1]}
sortedByValues.collect { |a| a[0] }.join ','