merging arrays of hashes - ruby

I have two arrays, each holding arrays with attribute hashes.
Array1 => [[{attribute_1 = A}, {attribute_2 = B}], [{attribute_1 = A}, {attribute_4 = B}]]
Array2 => [{attribute_3 = C}, {attribute_2 = D}], [{attribute_3 = C, attribute_4 = D}]]
Each array in the array is holding attribute hashes for an object. In the above example, there are two objects that I'm working with. There are two attributes in each array for each of the two objects.
How do I merge the two arrays? I am trying to get a single array of 'object' arrays (there is no way to get a single array from the start because I have to make two different API calls to get these attributes).
DesiredArray => [[{attribute_1 = A, attribute_2 = B, attribute_3 = C, attribute_4 = D}],
[{attribute_1 = A, attribute_2 = B, attribute_3 = C, attribute_4 = D}]]
I've tried a couple things, including the iteration methods and the merge method, but I've been unable to get the array I need.

You seem to have parallel arrays of hashes. We can use zip to turn the parallel arrays into a single array of arrays of hashes. We can then map each array of hashes into a single hash using inject and merge:
#!/usr/bin/ruby1.8
require 'pp'
array1 = [{:attribute_1 => :A, :attribute_2 => :B}, {:attribute_1 => :A, :attribute_4 => :B}]
array2 = [{:attribute_3 => :C, :attribute_2 => :D}, {:attribute_3 => :C, :attribute_4 => :D}]
pp array1.zip(array2).collect { |array| array.inject(&:merge) }
# => [{:attribute_2=>:D, :attribute_1=>:A, :attribute_3=>:C},
# => {:attribute_4=>:D, :attribute_1=>:A, :attribute_3=>:C}]

I don't think my answer is valid anymore, since the question has been edited later.
Here, first I am fixing your array and hash notation in your question.
Array1 = [{'attribute_1' => 'A', 'attribute_2' => 'B'}, {'attribute_1' => 'A', 'attribute_2' => 'B'}]
#=> [{"attribute_1"=>"A", "attribute_2"=>"B"}, {"attribute_1"=>"A", "attribute_2"=>"B"}]
Array2 = [{'attribute_3' => 'C', 'attribute_2' => 'D'}, {'attribute_3' => 'C', 'attribute_4' => 'D'}]
#=> [{"attribute_2"=>"D", "attribute_3"=>"C"}, {"attribute_3"=>"C", "attribute_4"=>"D"}]
You can simply concatenate the two arrays to get your desired array like so:
DesiredArray = Array1+Array2
# => [{"attribute_1"=>"A", "attribute_2"=>"B"}, {"attribute_1"=>"A", "attribute_2"=>"B", {"attribute_2"=>"D", "attribute_3"=>"C"}, {"attribute_3"=>"C", "attribute_4"=>"D"}]

Related

Find difference between arrays in Ruby, where the elements are hashes

I have two arrays of hashes I would like to find the difference between. My issue is the array elements are single item hashes.
So far, using array1 - array2 appears to be working correctly but do I need to watch out for gotchas here? The hash elements themselves read like h = {'ID' => '76322'}, where the numeric value differs from hash to hash, so nothing too fancy.
[EDIT]
Here's what I'm looking for:
array1 = []
array2 = []
h = {'ID' => '76322'}
array1.push(h)
h = {'ID' => '7891'}
array1.push(h)
array2.push(h)
array1 = array1 - array2 # should result in array1 having a single hash of values {'ID', '76322'}
array1 - array2 works by putting the elements of array2 into a temporary hash, then returning all elements of array1 that don't appear in the hash. Hash elements are compared using == to determine whether they match.
Comparing two hashes with == gives true if all the keys and values of the hashes match using ==. So
h1 = {'ID' => '7891'}
h2 = {'ID' => '7891'}
h1 == h2
evaluates to true, even though h1 and h2 are different hashes, and the corresponding elements will be correctly removed.
The only consideration I can think of is if you always have strings everywhere in the hash keys and values. If they are sometimes integers, or symbols, like {:ID => 7891} then you aren't going to get the results you want, because :ID == 'ID' and '7891' == 7891 are both false.

Creating array of hashes in ruby

I want to create an array of hashes in ruby as:
arr[0]
"name": abc
"mobile_num" :9898989898
"email" :abc#xyz.com
arr[1]
"name": xyz
"mobile_num" :9698989898
"email" :abcd#xyz.com
I have seen hash and array documentation. In all I found, I have to do something
like
c = {}
c["name"] = "abc"
c["mobile_num"] = 9898989898
c["email"] = "abc#xyz.com"
arr << c
Iterating as in above statements in loop allows me to fill arr. I actually rowofrows with one row like ["abc",9898989898,"abc#xyz.com"]. Is there any better way to do this?
Assuming what you mean by "rowofrows" is an array of arrays, heres a solution to what I think you're trying to accomplish:
array_of_arrays = [["abc",9898989898,"abc#xyz.com"], ["def",9898989898,"def#xyz.com"]]
array_of_hashes = []
array_of_arrays.each { |record| array_of_hashes << {'name' => record[0], 'number' => record[1].to_i, 'email' => record[2]} }
p array_of_hashes
Will output your array of hashes:
[{"name"=>"abc", "number"=>9898989898, "email"=>"abc#xyz.com"}, {"name"=>"def", "number"=>9898989898, "email"=>"def#xyz.com"}]
you can first define the array as
array = []
then you can define the hashes one by one as following and push them in the array.
hash1 = {:name => "mark" ,:age => 25}
and then do
array.push(hash1)
this will insert the hash into the array . Similarly you can push more hashes to create an array of hashes.
You could also do it directly within the push method like this:
First define your array:
#shopping_list_items = []
And add a new item to your list:
#shopping_list_items.push(description: "Apples", amount: 3)
Which will give you something like this:
=> [{:description=>"Apples", :amount=>3}]

How to add new item to hash

I don't know how to add new item to already existing hash. For example, first I construct hash:
hash = {item1: 1}
After that, I want to add item2, so after this I have hash like this:
{item1: 1, item2: 2}
I don't know what method to do on hash. Could someone help me?
Create the hash:
hash = {:item1 => 1}
Add a new item to it:
hash[:item2] = 2
If you want to add new items from another hash - use merge method:
hash = {:item1 => 1}
another_hash = {:item2 => 2, :item3 => 3}
hash.merge(another_hash) # {:item1=>1, :item2=>2, :item3=>3}
In your specific case it could be:
hash = {:item1 => 1}
hash.merge({:item2 => 2}) # {:item1=>1, :item2=>2}
but it's not wise to use it when you should to add just one element more.
Pay attention that merge will replace the values with the existing keys:
hash = {:item1 => 1}
hash.merge({:item1 => 2}) # {:item1=>2}
exactly like hash[:item1] = 2
Also you should pay attention that merge method (of course) doesn't effect the original value of hash variable - it returns a new merged hash. If you want to replace the value of the hash variable then use merge! instead:
hash = {:item1 => 1}
hash.merge!({:item2 => 2})
# now hash == {:item1=>1, :item2=>2}
hash.store(key, value) - Stores a key-value pair in hash.
Example:
hash #=> {"a"=>9, "b"=>200, "c"=>4}
hash.store("d", 42) #=> 42
hash #=> {"a"=>9, "b"=>200, "c"=>4, "d"=>42}
Documentation
It's as simple as:
irb(main):001:0> hash = {:item1 => 1}
=> {:item1=>1}
irb(main):002:0> hash[:item2] = 2
=> 2
irb(main):003:0> hash
=> {:item1=>1, :item2=>2}
hash[key]=value
Associates the value given by value with the key given by key.
hash[:newKey] = "newValue"
From Ruby documentation:
http://www.tutorialspoint.com/ruby/ruby_hashes.htm
hash_items = {:item => 1}
puts hash_items
#hash_items will give you {:item => 1}
hash_items.merge!({:item => 2})
puts hash_items
#hash_items will give you {:item => 1, :item => 2}
hash_items.merge({:item => 2})
puts hash_items
#hash_items will give you {:item => 1, :item => 2}, but the original variable will be the same old one.
Create hash as:
h = Hash.new
=> {}
Now insert into hash as:
h = Hash["one" => 1]

What are starred variables in Ruby?

What are starred variables like *arr?
*arr = "sayuj"
=> ["sayuj"]
*arr = *%w{i am happy}
=> ["i", "am", "happy"]
*arr = %w{i am happy}
=> [["i", "am", "happy"]]
It's called the splat operator, and it can collect elements into an array (applied to an un-bound variable) or split an array into individual elements (applied to an array).
def bar(*a)
a[1]
end
bar(1,2,3)
=> 2
def foo(a,b,c)
b
end
foo(*[1,2,3])
=> 2
That's a little over-simplified, read the linked post for more in-depth information.

Is saving a hash in another hash common practice?

I'd like to save some hash objects to a collection (in the Java world think of it as a List). I search online to see if there is a similar data structure in Ruby and have found none. For the moment being I've been trying to save hash a[] into hash b[], but have been having issues trying to get data out of hash b[].
Are there any built-in collection data structures on Ruby? If not, is saving a hash in another hash common practice?
If it's accessing the hash in the hash that is the problem then try:
>> p = {:name => "Jonas", :pos => {:x=>100.23, :y=>40.04}}
=> {:pos=>{:y=>40.04, :x=>100.23}, :name=>"Jonas"}
>> p[:pos][:x]
=> 100.23
There shouldn't be any problem with that.
a = {:color => 'red', :thickness => 'not very'}
b = {:data => a, :reason => 'NA'}
Perhaps you could explain what problems you're encountering.
The question is not completely clear, but I think you want to have a list (array) of hashes, right?
In that case, you can just put them in one array, which is like a list in Java:
a = {:a => 1, :b => 2}
b = {:c => 3, :d => 4}
list = [a, b]
You can retrieve those hashes like list[0] and list[1]
Lists in Ruby are arrays. You can use Hash.to_a.
If you are trying to combine hash a with hash b, you can use Hash.merge
EDIT: If you are trying to insert hash a into hash b, you can do
b["Hash a"] = a;
All the answers here so far are about Hash in Hash, not Hash plus Hash, so for reasons of completeness, I'll chime in with this:
# Define two independent Hash objects
hash_a = { :a => 'apple', :b => 'bear', :c => 'camel' }
hash_b = { :c => 'car', :d => 'dolphin' }
# Combine two hashes with the Hash#merge method
hash_c = hash_a.merge(hash_b)
# The combined hash has all the keys from both sets
puts hash_c[:a] # => 'apple'
puts hash_c[:c] # => 'car', not 'camel' since B overwrites A
Note that when you merge B into A, any keys that A had that are in B are overwritten.

Resources