JimboTwice
JimboTwice

Reputation: 117

Searching array of hashes to see if specific elements in a given hash match any string within another array in Ruby

Given the following code:

cons = [
  { "FirstName" => "Bill",
    "LastName" => "Wingy",
    "Phone1" => "(800) 552-3209",
    "Phone2" => "828 283-1134" 
  },
  { "FirstName" => "Ted",
    "LastName" => "Dimble",
    "Phone1" => "(823) 813-2834",
    "Phone2" => "8823 232-2342"
  }
]

pait_nums = [ "8282831134", "8282831132344" ]

How do you search the cons array to return the hash where either "Phone1".gsub(/\D/, '') or "Phone2".gsub(/\D/, '')matches any string within the pait_nums array?

Upvotes: 2

Views: 49

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110675

phones = ["Phone1", "Phone2"]
cons.find { |h| (h.values_at(*phones).map { |s| s.gsub(/\D/,"") } & pait_nums).any? }
  #=> {"FirstName"=>"Bill",
  #    "LastName"=>"Wingy",
  #    "Phone1"=>"(800) 552-3209",
  #    "Phone2"=>"828 283-1134"}

The steps:

find initially passes the first value of cons to the block and sets the block variable h to that value:

h = { "FirstName" => "Bill",
      "LastName" => "Wingy",
      "Phone1" => "(800) 552-3209",
      "Phone2" => "828 283-1134" }

The following block calculations are then performed:

a = h.values_at(*phones)
  #=> ["(800) 552-3209", "828 283-1134"]
b = a.map { |s| s.gsub(/\D/,"") }
  #=> ["8005523209", "8282831134"]
c = b & pait_nums
  #=> ["8005523209", "8282831134"] & ["8282831134", "8282831132344"]
  #=> ["8282831134"]
c.any?
  #=> true

As c is true, find returns h. Were c false, the second hash would be sent to the block.

Upvotes: 2

Hieu Pham
Hieu Pham

Reputation: 6707

Let try this:

cons.select{ |con| pait_nums.include?(con['Phone1'].gsub(/\D/, '')) || pait_nums.include?(con['Phone2'].gsub(/\D/, '')) }

Or make it shorter

phone_keys = %w( Phone1 Phone2 )
cons.select{ |con| con.slice(*phone_keys).values.any?{ |val| pait_nums.include?(val.gsub(/\D/, '')) } }

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

cons.select do |c|
  c.select do |k, _|
    k =~ /\APhone\d\z/                     # select Phone* keys
  end.values                               # get values
     .any? do |p|
       pait_nums.include? p.gsub(/\D/, '') # get only matches
     end
end

or, for any arbitrary set of keys to check:

keys = %w|Phone1 Phone2|
cons.select do |c|
  c.select do |k, _|
    keys.include? k                        # select Phone* keys
  end.values.any? do |p|
    pait_nums.include? p.gsub(/\D/, '')    # get only matches
  end
end

Upvotes: 0

Vishal Jain
Vishal Jain

Reputation: 1940

If you are using rails then you can use presentin ruby you can use any?

cons.select{ |con| ([con['Phone1'].gsub(/\D/, ''), con['Phone2'].gsub(/\D/, '')] & pait_nums).present?}

In ruby you can use any? as

 cons.select{ |con| ([con['Phone1'].gsub(/\D/, ''), con['Phone2'].gsub(/\D/, '')] & pait_nums).any?}

Upvotes: 0

Related Questions