0

I have a use case where I want to fetch keys from a hash which are present in a separate array.

Example:

h = {"video"=>"MP4", "audio"=>"MP3", "sharing"=>"NONE", "mix"=>"NONE"}
a = ["video", "audio", "txt"]

Expected result:

["video", "audio"]

I am trying to use slice method on hash but it is not working for me:

h.slice(a)

Any help would be appreciated.

2
  • do u want to fetch only keys or keys with their values? Commented Jul 28, 2022 at 17:57
  • 4
    You want a = ["video", "audio", "txt"] ({"video", "audio", "txt"} is an invalid expression). If you want all keys of h that are in a, h.keys & a #=> ["video", "audio"]. If you want all key-value pairs in h for which the key is in a, h.slice(*a) #=> {"video"=>"MP4", "audio"=>"MP3"}. Commented Jul 28, 2022 at 18:29

3 Answers 3

1

The reason you attempt doesn't work is that hash keys can actually be any kind of object and Hash#slice will compare them by identity:

# its a hash with array keys - crazy stuff.
=> {[1, 2, 3]=>"a", [3, 4, 5]=>"b"}
irb(main):012:0> hash.slice([1,2,3])
=> {[1, 2, 3]=>"a"}
# [1,2,3] and [1,2] are not equal
irb(main):013:0> hash.slice([1,2])
=> {}
irb(main):014:0> hash.slice([3,4,5])
=> {[3, 4, 5]=>"b"}
irb(main):015:0> 

An array will never be equal to a string in Ruby.

If you want to convert an array into a list of arguments to pass to a method use the splat operator (*):

irb(main):022:0> h = {"video"=>"MP4","audio"=>"MP3", "sharing"=>"NONE", "mix"=>"NONE"}
=> {"video"=>"MP4", "audio"=>"MP3", "sharing"=>"NONE", "mix"=>"NONE"}
irb(main):023:0> a = ["video", "audio", "txt"]
=> ["video", "audio", "txt"]
irb(main):024:0> h.slice(*a)
=> {"video"=>"MP4", "audio"=>"MP3"}
Sign up to request clarification or add additional context in comments.

Comments

1

You can do an intersection using &. For example:

2.7.2 :001 > h = {"video"=>"MP4", "audio"=>"MP3", "sharing"=>"NONE", "mix"=>"NONE"}
 => {"video"=>"MP4", "audio"=>"MP3", "sharing"=>"NONE", "mix"=>"NONE"}
2.7.2 :002 > a = ["video", "audio", "txt"]
 => ["video", "audio", "txt"]
2.7.2 :003 > h.keys & a
 => ["video", "audio"]
2.7.2 :004 >

The explanation is: you got array of keys from hash(h.keys) and them get the intersection between array of keys and the array using &

Comments

1

You can try filter with a proc (which checks for h key inclusion):

a.filter(&h.method(:key?))

which is essentially the same as using a block:

a.filter { |a_i| h.key?(a_i) }

You can also use intersection with keys (this approach kind of steps on other answers with & operator here):

a.intersection(h.keys)

and you're going to get the following result with any of the solutions above:

=> ["video", "audio"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.