How to convert array of 3 element arrays in to a hash where key is first 2 elements

My problem is that I need to do efficient lookups of if a 2 element array and their corresponding value is nil. So if I have the following arrays:

arr1 = [
  [1, 2, 100],
  [3, 4, nil],
  [5, 6, 101]
]

I want something like

h = {
  [1, 2] => 100,
  [3, 4] => nil,
  [5, 6] => 101
}

So I can do something like:

error = []
arr2 = [
  [1,2],
  [3,4],
  [7,8]
]

arr2.each do |val|
  if h.include?(val)
    if h[val] == nil
      error << "Value is nil"
    else
      # Do something
    end
  else
    error << "Key doesn't exist"
  end
end

>Solution :

Given that overwriting or ignoring duplicates is acceptable per your comment.

You can use Enumerable#each_with_object to iterate the Array and create a Hash like so

arr1 = [
  [1, 2, 100],
  [3, 4, nil],
  [5, 6, 101],
  [1, 2, nil],
]

arr1.each_with_object({}) do |(*first_two,last),obj| 
  obj[first_two] = last
end 
#=> {[1, 2]=>nil, [3, 4]=>nil, [5, 6]=>101}

You can ignore duplicates in a similar fashion

arr1.each_with_object({}) do |(*first_two,last),obj| 
  obj[first_two] = last unless obj.key?(first_two)
end 
#=> {[1, 2]=>100, [3, 4]=>nil, [5, 6]=>101}

Explanation:

  • each_with_object({}) will pass each element of of arr1 to the block along with an object (a Hash in this case)

  • (*first_two,last),obj*first_two will collect everything up to last and obj is our Hash

  • obj[first_two] = last simple Hash key assignment

  • each_with_object returns the object (obj Hash in this case)

Leave a Reply