Martijn Kerckhaert
Martijn Kerckhaert

Reputation: 494

Find key of value within array in hash

I have a hash categories as following:

categories = {"horeca" => ["bar", "waiter", "kitchen"], 
              "retail" => ["eerste", "tweede"]}

I want to find they key if the value is included in the array of values.

Something like following

categories.key("bar")

which would return "horeca"

as of now I can only get "horeca" if I do

categories.key(["bar", "waiter", "kitchen"])

Upvotes: 4

Views: 12269

Answers (4)

Clemens Kofler
Clemens Kofler

Reputation: 1968

Md. Farhan Memon's solution is generally the preferable solution but it has one downside: If there's no match in the collection, it returns the collection itself – which probably isn't a desirable result. You can fix this with a simple adjustment that combines both detect/find and break:

categories.detect { |key, values| break key if values.include?('bar') }

This breaks and returns the value if it finds it and otherwise returns nil (which I assume to be the preferable behavior).

If your collection may also contain nil values and/or non-arrays, you can improve it further:

categories.detect { |key, values| break key if Array(values).include?('bar') }

The only downside of this general approach is that it's not particularly intuitive to newcomers: You have to know a bit more than just basic Ruby to understand what's going on without running the code first.

Upvotes: 3

Md. Farhan Memon
Md. Farhan Memon

Reputation: 6121

Creating intermediate array and then calling first on it is all unnecessary, also if the hash is large and you want first matched value, following solution is better

categories.each{ |k,v| break k if v.include?('bar') }
#=> "horeca"

Upvotes: 3

tpei
tpei

Reputation: 681

As Máté mentioned, you can use find if you want to find the first matching element. Use select if you want all matching elements. To just get the keys you would do:

categories.select { |key, values| values.include?("bar") }.map(&:first)

See https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select

Upvotes: 5

Mate Solymosi
Mate Solymosi

Reputation: 5977

Try Enumberable#find:

categories.find { |key, values|
  values.include?("bar")
}.first

Upvotes: 7

Related Questions