In the following nested hash,
hash = {a: 2, b: 4, c: {name: "John", id: 12, age: 33}}
I want to return the values that are hash:
{:name => "John", :id => 12, :age => 33}
I want to returned a hash. I thought the following code will do the job:
hash.select! {|_k, v| v.is_a?(Hash)}
# => {:c => {:name => "John", :id => 12, :age => 33}}
but I get both k/v pairs. Did I miss anything on the code? How can I achieve the return value as mentioned?
I would do something like:
hash.values.find(&Hash.method(:===))
#=> {:name=>"John", :id=>12, :age=>33}
select returns the key and value that matched. Add .values to get just the values without the keys:
hash.select! { |_k, v| v.is_a?(Hash) }.values
This will return an array of the values that were matched by select:
[{:name=>"John", :id=>12, :age=>33}]
If you know there will only ever be one result, you can get the desired value by calling first:
hash.select! { |_k, v| v.is_a?(Hash) }.values.first
{:name=>"John", :id=>12, :age=>33}
I have a two dimensional hashes in Ruby.
h = { "a" => {"v1" => 0, "v2" => 1}, "c" => {"v1" => 2, "v2" => 3} }
I would like to delete those elements from the hash, where value 1 (v1) is 0, for example, so my result would be:
{ "c" => {"v1" => 2, "v2" => 3} }
I wanted to achieve this by iterating trough the hash with delete_if, but I'm not sure how to handle the nested parts with it.
Is that what you're looking for?
h.delete_if { |_, v| v['v1'].zero? }
#=> {"c" => {"v1" => 2, "v2" => 3}}
As #TomLord says, it also may be variant, when v1 can be not defined or equal to nil, in this case, it would be better to use v['v1'] == 0
You can use Hash#value? in your block to check if any of the values in the nested hashes equal 0:
hash.delete_if { |k,v| v.value? 0 } #=> { "c" => { "v1" => 2, "v2" => 3 } }
I have an array of hashes, id being one of the keys in the hashes. I want to sort the array elements according to a given order of ID values.
Suppose my array(size=5) is:
[{"id"=>1. ...}, {"id"=>4. ...}, {"id"=>9. ...}, {"id"=>2. ...}, {"id"=>7. ...}]
I want to sort the array elements such that their ids are in the following order:
[1,3,5,7,9,2,4,6,8,10]
So the expected result is:
[{'id' => 1},{'id' => 7},{'id' => 9},{'id' => 2},{'id' => 4}]
Here is a solution for any custom index:
def my_index x
# Custom code can be added here to handle items not in the index.
# Currently an error will be raised if item is not part of the index.
[1,3,5,7,9,2,4,6,8,10].index(x)
end
my_collection = [{"id"=>1}, {"id"=>4}, {"id"=>9}, {"id"=>2}, {"id"=>7}]
p my_collection.sort_by{|x| my_index x['id'] } #=> [{"id"=>1}, {"id"=>7}, {"id"=>9}, {"id"=>2}, {"id"=>4}]
Then you can format it in any way you want, maybe this is prettier:
my_index = [1,3,5,7,9,2,4,6,8,10]
my_collection.sort_by{|x| my_index.index x['id'] }
I would map the hash based on the values like so:
a = [{"id"=>1}, {"id"=>4}, {"id"=>9}, {"id"=>2}, {"id"=>7}]
[1,3,5,7,9,2,4,6,8,10].map{|x| a[a.index({"id" => x})] }.compact
#=> [{"id"=>1}, {"id"=>7}, {"id"=>9}, {"id"=>2}, {"id"=>4}]
General note on sorting. Use #sort_by method of the ruby's array class:
[{'id' => 1},{'id'=>3},{'id'=>2}].sort_by {|x|x['id'] }
# => [{"id"=>1}, {"id"=>2}, {"id"=>3}]
Or with usage #values method as a callback:
[{'id' => 1},{'id'=>3},{'id'=>2}].sort_by(&:values)
# => [{"id"=>1}, {"id"=>2}, {"id"=>3}]
or you can use more obvious version with #sort method:
[{'id' => 1},{'id'=>3},{'id'=>2}].sort {|x,y| x['id'] <=> y['id'] }
# => [{"id"=>1}, {"id"=>2}, {"id"=>3}]
For your case, to sort with extended condition use #% to split even and odd indexes:
[{'id' => 1},{'id'=>4},{'id'=>9},{'id'=>2},{'id'=>7}].sort do |x,y|
u = y['id'] % 2 <=> x['id'] % 2
u == 0 && y['id'] <=> x['id'] || u
end
# => [{"id"=>1}, {"id"=>7}, {"id"=>9}, {"id"=>2}, {"id"=>4}]
For your case, to sort with extended condition use #% to split according the index, even id value is absent in the index array:
index = [1,3,5,7,4,2,6,8,10] # swapped 2 and 4, 9 is absent
[{'id' => 1},{'id'=>4},{'id'=>9},{'id'=>2},{'id'=>7}].sort do |x,y|
!index.rindex( x[ 'id' ] ) && 1 || index.rindex( x[ 'id' ] ) <=> index.rindex( y[ 'id' ] ) || -1
end
# => [{"id"=>1}, {"id"=>7}, {"id"=>4}, {"id"=>2}, {"id"=>9}]
Why not just sort?
def doit(arr, order)
arr.sort { |h1,h2| order.index(h1['id']) <=> order.index(h2['id']) }
end
order = [1,3,5,7,9,2,4,6,8,10]
arr = [{'id' => 1}, {'id' => 4}, {'id' => 9}, {'id' => 2}, {'id' => 7}]
doit(arr, order)
#=> [{'id' => 1}, {'id' => 7}, {'id' => 9}, {'id' => 2}, {'id' => 4}]
a= [{"id"=>1}, {"id"=>4}, {"id"=>9}, {"id"=>2}, {"id"=>7}]
b=[1,3,5,7,9,2,4,6,8,10]
a.sort_by{|x| b.index (x['id'])}
I've got an unsorted array of keys like this:
keys = ["ccc", "ddd", "ggg", "aaa", "bbb"]
and a hash
hash = {"ddd" => 4, "aaa" => 1, "bbb" => 2, "eee" => 5, "fff" => 6}
I'd like to join these two data structures to return a hash in the original order of keys to the first keys:
{"ccc" => nil, "ddd" => 4, "ggg" => nil, "aaa" => 1, "bbb" => 2}
Items NOT in the hash (like "ggg") should return nil.
This is analogous to the "v-lookup" function in excel.
this is in ruby. Thanks!
Cryptic:
Hash[keys.zip(hash.values_at *keys)]
Or a bit longer, a bit less cryptic:
keys.map.with_object({}) {|key, memo| memo[key] = hash[key]}
Is there a simple way of remapping a hash in ruby the following way:
from:
{:name => "foo", :value => "bar"}
to:
{"foo" => "bar"}
Preferably in a way that makes it simple to do this operation while iterating over an array of this type of hashes:
from:
[{:name => "foo", :value => "bar"}, {:name => "foo2", :value => "bar2"}]
to:
{"foo" => "bar", "foo2" => "bar2"}
Thanks.
arr = [ {:name=>"foo", :value=>"bar"}, {:name=>"foo2", :value=>"bar2"}]
result = {}
arr.each{|x| result[x[:name]] = x[:value]}
# result is now {"foo2"=>"bar2", "foo"=>"bar"}
A modified version of Vanson Samuel's code does the intended.
It's a one-liner, but quite a long one.
arr = [{:name=>"foo", :value=>"bar"}, {:name=>"foo2", :value=>"bar2"}]
arr.inject({}){|r,item| r.merge({item['name'] => item['value']})}
# result {"foo" => "bar", "foo2" => "bar2"}
I wouldn't say that it's prettier than Gishu's version, though.
As a general rule of thumb, if you have a hash of the form {:name => "foo", :value => "bar"}, you're usually better off with using a tuple of ["foo", "bar"].
arr = [["foo", "bar"], ["foo2", "bar2"]]
arr.inject({}) { |accu, (key, value)| accu[key] = value; accu }
I know this is old, but the neatest way to achieve this is to map the array of hashes to an array of tuples, then use Hash[] to build a hash from that, as follows:
arr = [{:name => "foo", :value => "bar"}, {:name => "foo2", :value => "bar2"}]
Hash[ array.map { |item| [ item[:name], item[:value] ] } ]
# => {"foo"=>"bar", "foo2"=>"bar2"}
a bit late but:
[{ name: "foo", value: "bar" },{name: "foo2", value: "bar2"}].map{ |k| k.values }.to_h