Taking values from a Ruby array of hashes - ruby-on-rails

I have an array of hashes:
a = [{"Key1"=>"Value1", "Key2"=>"Value2"},
{"Key1"=>"Value3", "Key2"=>"Value4"},
{"Key1"=>"Value5", "Key2"=>"Value6"}]
Basically I am trying to get an output with only values and not any keys. Something like this
['Value1', 'Value2', 'Value3', 'Value4', 'Value5', 'Value6']
Here is the code which I tried. As key1 and key2 are the same, I stored both the keys in an array....
k = ["key1", "key2"]
for i in 0..a.length
k.each do |key_to_delete|
a[i].delete key_to_delete unless a[i].nil?
end
end
However, this removes all values and I get an empty array. Any help is appreciated.

You can use Enumerable#flat_map and fetch values from each hash:
a.flat_map(&:values)
=> ["Value1", "Value2", "Value3", "Value4", "Value5", "Value6"]
This is an answer on the original question.

Related

Splitting values in Hash

I have a Hash in the following format:
{"PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548", "6e90208e-4ab2-4d44-bbaa-9a874bff095b"], "Amount"=>"[\"10000.000\", \"2374.000\"]"}
When I write this data into an excel get the following output.
I want to write the data into the Excel this way:
PPS_Id Amount
fe4d7c06-215a-48a7-966d-19ab58976548 10000.000
6e90208e-4ab2-4d44-bbaa-9a874bff095b 2374.000
How do I convert my current Hash to the below?
{PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548","Amount"=>"10000.000"},{PPS_Id"=>["6e90208e-4ab2-4d44-bbaa-9a874bff095b","Amount"=>"2374.000"}
Can you please assist.
If you can modify your original hash from
hash = {"PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548", "6e90208e-4ab2-4d44-bbaa-9a874bff095b"], "Amount"=>"[\"10000.000\", \"2374.000\"]"}
to
hash = {"PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548", "6e90208e-4ab2-4d44-bbaa-9a874bff095b"], "Amount"=>["10000.000", "2374.000"]}
Note: the last value in the hash is an Array instead of a String.
Then, you can generate an Array of hashes on which you can iterate to fill your excel:
ary = hash.inject([]) do |r, (key, value)|
value.each_with_index do |e, i|
r[i] ||= {}
r[i][key] = e
end
r
end
ary # [{"PPS_Id"=>"fe4d7c06-215a-48a7-966d-19ab58976548", "Amount"=>"10000.000"}, {"PPS_Id"=>"6e90208e-4ab2-4d44-bbaa-9a874bff095b", "Amount"=>"2374.000"}]
If your hash really looks like this :
hash = {"PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548", "6e90208e-4ab2-4d44-bbaa-9a874bff095b"],
"Amount"=>"[\"10000.000\", \"2374.000\"]"}
you can use scan to parse the floats first :
hash["Amount"] = hash["Amount"].scan(/[\d\-\.]+/)
Your hash will now look like :
{"PPS_Id"=>["fe4d7c06-215a-48a7-966d-19ab58976548", "6e90208e-4ab2-4d44-bbaa-9a874bff095b"],
"Amount"=>["10000.000", "2374.000"]}
To get the table you want, you could just transpose the hash values :
hash.values_at("PPS_Id", "Amount").transpose.each{|id, amount|
puts format("%s\t%.3f", id, amount)
}
It will output :
fe4d7c06-215a-48a7-966d-19ab58976548 10000.000
6e90208e-4ab2-4d44-bbaa-9a874bff095b 2374.000

match key of hash and then fetch values accordingly in ruby

I have included the given code:
#classes = {1=>"USA", 3=>"France", 2=>"UK", 5=>"Europe", 7=>"Delhi", 8=>"test"}
#amaze = params[:test] #I get "1,3,7"
I get this, now please guide me how to match keys with #amaze and accordingly fetch its values from #classes i.e USA, France, Delhi.
Since #amaze is just a String, lets first convert it in Array so its easy to enumerate:
#amaze = "1,3,7"
#amaze = #amaze.split(",")
# => ["1", "3", "7"]
Now, since you have all keys extract all values:
#amaze.map { |i| #classes[i.to_i] }
# => ["USA", "France", "Delhi"]
Split #amaze by , and get an array of keys, convert them into Integer, then select only those key/value pairs which key is into this array of keys. Something like this:
#classes = {1=>"USA", 3=>"France", 2=>"UK", 5=>"Europe", 7=>"Delhi", 8=>"test"}
#amaze = "1,3,7" #I get "1,3,7"
arr = #amaze.split(',').map(&:to_i)
p #classes.select{|el| arr.include? el}
Result:
#> {1=>"USA", 3=>"France", 7=>"Delhi"}
If you want values only use .values:
p #classes.select{|el| arr.include? el}.values
Result:
#> ["USA", "France", "Delhi"]
For what(seemingly) you are asking, the below line will do it:
#amaze.split(",").each { |i| p #classes[i.to_i] }
# If #amaza = "1,3,7", above line will output:
# => "USA"
# "France"
# "UK"
This should work well for you:
#classes = {1=>"USA", 3=>"France", 2=>"UK", 5=>"Europe", 7=>"Delhi", 8=>"test"}
#amaze = params[:test].split(",").map(&:to_i)
#classes.values_at(*#amaze)
#=> ["USA", "France", "Delhi"]
Hash#values_at accepts an indefinite number of keys and returns their values as an array. The * (splat) operator explodes the array so this call actually becomes #classes.values_at(1,3,7) Docs
Might also want to add a compact to the end in the event a key does not exist. e.g
#amaze = params[:test].split(",").map(&:to_i) # Asssume this returns [1,3,7,9]
#classes.values_at(*#amaze)
#=> ["USA", "France", "Delhi",nil]
#classes.values_at(*#amaze).compact
#=> ["USA", "France", "Delhi"]
I think a clearer understanding of hashes would help you out here.
A Hash is a data structure that is a list of key-value pairs. For example, the following is a Hash object of key-value pairs (your example):
#classes = {1=>"USA", 3=>"France", 2=>"UK", 5=>"Europe", 7=>"Delhi", 8=>"test"}
If you want to extract a value from #classes, you need to pass the key of the value you want. If we wanted "USA" we would pass the key of 1 to #classes. If we wanted "France", we would pass it the key of 3:
#classes[1] would return "USA" and #classes[3] would return "France".
It's not clear what data structure #amaze is according to your question, but let's say it's the string "1, 3, 7" which we can split to create an array [1, 3, 7].
You could iterate over the array to get each of the values from #classes:
#amaze.split(",").map(&:to_i).each do |key|
puts #classes[key]
end
That would print out each of the corresponding values to keys in #classes.

Ruby Array Having Hash Pairs?

I have the ruby array as following :
array = [{"id"=>8, "book_id"=>14238}, {"id"=>5, "book_id"=>14238}, {"id"=>7, "book_id"=>10743}, {"id"=>9, "book_id"=>10743}]
I want a new array combining the result of ids having same book_id.
Expected Result:
array = [{"book_id"=>14238, "id"=>[8,5]}, {"book_id"=>10743, "id"=>[7,9]}]
I can't say that this is easy to understand, but it is concise:
array.group_by {|item| item["book_id"] }.map do |k, v|
{ "book_id" => k, "id" => v.map {|item| item["id"] } }
end
=> [{"book_id"=>14238, "id"=>[8, 5]}, {"book_id"=>10743, "id"=>[7, 9]}]
The first transformation done by group_by rearranges your array so that items with the same book_id are grouped together:
array.group_by {|item| item["book_id"] }
=> {14238=>[{"id"=>8, "book_id"=>14238}, {"id"=>5, "book_id"=>14238}], 10743=>[{"id"=>7, "book_id"=>10743}, {"id"=>9, "book_id"=>10743}]}
The second transformation (map) reformats the hash produced by the group_by into a list of hashes, and the second map collects the id's into a list.
You can also do this using the form of Hash#update (a.k.a. merge!) that employs a block to resolve the values of keys that are contained in both of the hashes being merged.
Code
def aggregate(arr)
arr.each_with_object({}) do |g,h|
f = { g["book_id"]=>{ "id"=>[g["id"]], "book_id"=>g["book_id"] } }
h.update(f) do |_,ov,nv|
ov["id"] << nv["id"].first
ov
end
end.values
end
Example
arr = [{"id"=>8, "book_id"=>14238}, {"id"=>5, "book_id"=>14238},
{"id"=>7, "book_id"=>10743}, {"id"=>9, "book_id"=>10743},
{"id"=>6, "book_id"=>10511}]
aggregate(arr)
#=> [{"id"=>[8, 5], "book_id"=>14238},
# {"id"=>[7, 9], "book_id"=>10743},
# {"id"=>[6], "book_id"=>10511}]
Alternative output
Depending on your requirements, you might consider building a single hash instead of another array of hashes:
def aggregate(arr)
arr.each_with_object({}) { |g,h|
h.update({ g["book_id"]=>[g["id"]] }) { |_,ov,nv| ov+nv } }
end
aggregate(arr)
#=> {14238=>[8, 5], 10743=>[7, 9], 10511=>[6]}
I'd use a hash for the output for easier lookups and/or reuse:
array = [{"id"=>8, "book_id"=>14238}, {"id"=>5, "book_id"=>14238}, {"id"=>7, "book_id"=>10743}, {"id"=>9, "book_id"=>10743}]
hash = array.group_by{ |h| h['book_id'] }.map{ |k, v| [k, v.flat_map{ |h| h['id'] }]}.to_h
# => {14238=>[8, 5], 10743=>[7, 9]}
The keys are the book_id values, and the associated array contains the id values.
The expected result of
array = [{"book_id"=>14238, "id"=>[8,5]}, {"book_id"=>10743, "id"=>[7,9]}]
isn't a good structure if you're going to do any sort of lookups in it. Imagine having hundreds or thousands of elements and needing to find "book_id" == 10743 in the array, especially if it's not a sorted list; The array would have to be walked until the desired entry was found. That is a slow process.
Instead, simplify the structure to a simple hash, allowing you to easily locate a value using a simple Hash lookup:
hash[10743]
The lookup will never slow down.
If the resulting data is to be iterated in order by sorting, use
sorted_keys = hash.keys.sort
and
hash.values_at(*sorted_keys)
to extract the values in the sorted order. Or iterate over the hash if the key/values need to be extracted, perhaps for insertion into a database.

How to insert an array to an existing hash array in Ruby?

I have a current array of the below hash map, i have another array that i would like to insert into each hash by matching on the id.
{"url"=>"http://ubuntu64:1990/getpages",
"id"=>"32794",
"version"=>"2",
"title"=>"Creating a page",
"space"=>"test",
"parentId"=>"32782",
"permissions"=>"0"}
The other array i want to add the 'imageurl' key/value based on the id, so something like (if id == id insert 'imageurl'/'someurl.jpg}
{"id"=>"32794", "imageurl" => "someurl.jpg}
array = [...] #Declare your array with the "big" hashes here
array2 = [...] #Declare your array with the hash containing the imageurl key here
array.each do |a|
array2.each do |a2|
if a[:id] == a2[:id]
a[:imageurl] = a2[:imageurl]
break #We found it
end
end
end
Should do the trick ... maybe there's a smarter way to do it though

how to take a hash and turn into an array

I want to be able to take the following:
{"6"=>"", "7"=>"104", "8"=>"", "9"=>"", "0"=>"Testing", "2"=>"1", "3"=>"", "10"=>"Testing", "4"=>"1", "5"=>""}
and convert it into
[["","104","","","Testing"........], ["" ......]
Thank you
The Hash class has the method values which returns an array of all the values.
my_hash = {"6" => "", "7" => "104"}
my_array_of_values = my_hash.values # ["", "104"]
In Ruby, the Hash contains key/value pairs (eg. { key => value }). The keys method returns an array of the keys and the values method returns an array of the values.
Read more about the values method here:
http://ruby-doc.org/core/classes/Hash.html#M002867

Resources