Merging hashes into arrays - arrays

I'm new in Ruby. I have two arrays of hashes
arr1 = [{"one"=> {"1"=> "a", "2" => "b"}, "two" => {"3" => "n", "5" => "h", "7" => "k"}]
arr2 = [{"one"=> {"8"=> "f", "11" => "r"}, "two" => {"7" => "o", "6" => "b", "14" => "b"}]
and I want to have one array like this:
arr3 = [{
"one"=> {"1"=> "a", "2" => "b", "8"=> "f", "11" => "r"},
"two" => {3" => 'n", "5" => "h", "7" => "k", 7" => 'o", "6" => "b", "14" => "b"}
]
so I want to merge hashes by keys and "add" their values. Can anyone help?

arr1 = [{"one"=>{"1"=>"a", "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h", "7"=>"k"}}]
arr2 = [{"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}]
(arr1+arr2).each_with_object({}) { |g,h| h.update(g) { |_,o,n| o.merge(n) } }
# => {"one"=>{"1"=>"a", "2"=>"b", "8"=>"f", "11"=>"r"},
# "two"=>{"3"=>"n", "5"=>"h", "7"=>"o", "6"=>"b", "14"=>"b"}}
This uses the form of Hash#update (aka merge!) that uses a block ({ |_k,o,n| o.merge(n) }) to determine the value of the key _k when both hashes being merged have that key. (_ in _k tells the reader that that block variable is not used in the block calculation.) o and n are the values of that key in h and g respectively.
For each key k equal to "one" or "two", if the values (hashes) of arr1.first[k] and arr2.first[k] have a common key l, the merge operation will cause the value of l in arr1 will be overwritten by the value of l in arr2. If, for example, arr1.first["one"] #=> {"1"=>"a", "2"=>"b"} and arr2.first["one"] #=> {"8"=>"f", "2"=>"r"}, the merge will return {"1"=>"a", "2"=>"r", "8"=>"f"}
Even though arr1 and arr2 each contain a single element (a hash), the code above works fine when the arrays contain multiple hashes, and when there are more than two arrays. If the arrays always contain a single hash, the arrays serve no purpose and we might instead just reference the hashes:
h1 = {"one"=>{"1"=>"a", "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h", "7"=>"k"}}
h2 = {"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}
and replace arr1+arr2 with [h1+h2].

Maybe not the most elegant but this works:
arr1 = [{"one"=>{"1"=>"a", "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h", "7"=>"k"}}]
arr2 = [{"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}]
arr3 = []
arr1[0].each_key{|k| arr3<< {k => arr1[0][k].merge(arr2[0][k])}}
arr3
If you don't know how many hashes your original array will contain, simply replace arr1[0].each_key with arr1.each_index{|i| arr1[i].each_key and replace 0 with i in the merge.

Related

How to get an array of all keys in a Dictionary?

How can one get all the keys of a dictionary as a separate array in Julia.
For example:
Dict("a" => 123, "b" => 456, "c" => 789)
would give the following Array:
["a", "b", "c"]
Here is how you can do it (if an iterator is enough for you just use keys to avoid materializing the array):
julia> d = Dict("a" => 123, "b" => 456, "c" => 789)
Dict{String, Int64} with 3 entries:
"c" => 789
"b" => 456
"a" => 123
julia> keys(d)
KeySet for a Dict{String, Int64} with 3 entries. Keys:
"c"
"b"
"a"
julia> collect(keys(d))
3-element Vector{String}:
"c"
"b"
"a"

How to sort hashes in an array by keys?

Eg:
arr = ["c", "e", "a", {"hello" => [1,2,3]}, {"bell" => [4,5,6]}]
Above variable refers to an array which contains hashes along with strings. I need to write a function to sort this array alphabetically while the hashes being sorted by keys. Ideally it has to return the following:
["a", {"bell" => [4,5,6]}, "c", "e", {"hello" => [1,2,3]}]
array.sort_by {|a| a.is_a?(Hash) ? a.keys.first : a }

How do I find an index of an element in an array matching a condition and starting the search from a particular point in the array?

I'm using Ruby 2.4. I know how to find all the indexes in an array of elements matching a condition ...
arr.each_index.select{|i| arr[i] == 'x'}
but how do I find the index of the first element that matches a condition starting from a particular position in teh array? So what if I wanted to find a string with only a single character at or after index = 2? (If tehre are less than 2 elements the operation can return nil). So for example, if I have
["abc", "d", "efg", "h", "abcde"]
the operation would return "3", since element "h" is at position 3, only has a single character and is at or after index 2.
Using select would return all values where the block returns true for example:
p arr = ["abc", "d", "efg", "h", "abcde", "k"]
# => ["abc", "d", "efg", "h", "abcde", "k"]
p arr.each_index.select{|i| i >= 2 and arr[i].length == 1}
# => [3, 5]
Instead use detect if you want to return only the first value where the block returns true:
p arr = ["abc", "d", "efg", "h", "abcde", "k"]
# => ["abc", "d", "efg", "h", "abcde", "k"]
p arr.each_index.detect{|i| i >= 2 and arr[i].length == 1}
# => 3
Use Array#index with with_index:
arr = ["abc", "d", "efg", "h", "abcde"]
arr.index.with_index { |el, idx| el.length == 1 && idx > 2 }
=> 3
arr = ["abc", "d"]
arr.index.with_index { |el, idx| el.length == 1 && idx > 2 }
=> nil
def first_index_after(arr, min_ndx)
min_ndx.upto(arr.size-1).find { |i| yield(arr[i]) }
end
arr = ["abcdef", "h", "efgh", "h", "abcde", "h"]
min_ndx = 2
first_index_after(arr, min_ndx) { |e| e == "h" } #=> 3
first_index_after(arr, min_ndx) { |e| e =~ /\Ah\z/ } #=> 3
first_index_after(arr, min_ndx) { |e| e =~ /h/ } #=> 2
first_index_after(arr, min_ndx) { |e| e.size > 4 } #=> 4
first_index_after(arr, min_ndx) { |e| e == 'cat' } #=> nil
This assumes 0 <= min_ndx < arr.size. It may be desirable to add a first line to the method that returns nil or raises an exception if this requirement is not satisfied.

Ruby Hash Values is Array, need to convert to string

I have a hash of integers as keys and arrays of strings as values. I need to convert this to a new hash that inverts this relationship with each item from the array of strings in the original hash values becoming a key in the new hash and each original key becoming the associated value. For example:
original = {1 => ['a', 'b', 'c'], 2 => ['g', 'm', 'z']}
new_hash = {'a' => 1, 'b' => 1, 'c' => 1, 'g' => 2, 'm' => 2, 'z' => 2}
I'm struggling to extract the items from the original array values. It's easy enough to do
original.each { |k, v| new_hash[v] = k }
but this keeps the original array as the new key. I've tried doing something like
original.each { |k, v| new_hash[v.each { |i| i }] = k }
but this also returns the original array for some reason.
Another one, via Array#product:
original.flat_map { |k, v| v.product([k]) }.to_h
#=> {"a"=>1, "b"=>1, "c"=>1, "g"=>2, "m"=>2, "z"=>2}
original.flat_map { |k, vs| vs.map { |v| {v => k} } }.reduce(&:merge)
the below snippet will give what you want, but let me think on a more readable and elegant solution.
newhash = {}
original.each do |k,v|
v.each do |v2|
newhash[v2] = k
end
end
#=> {1=>["a", "b", "c"], 2=>["g", "m", "z"]}
newhash
#=> {"a"=>1, "b"=>1, "c"=>1, "g"=>2, "m"=>2, "z"=>2}
Your approach is close. You'll have to iterate each element in the values array when assigning the new key/value pair to the newHash
newHash = {}
original.each { |k, v| v.each {|i| newHash[i] = k}}
original.map { |number, ary| Hash[ary.map { |char| [char, number] }] }.reduce(&:merge)

Converting array of stringified key value pairs to hash in Ruby

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"}.
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" }
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"}
Try this
array.map {|s| s.split('=')}.to_h
=> {"Name "=>" abc", "Id "=>" 123", "Interest "=>" Rock Climbing"}
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.

Resources