in reply to Re: Intersect two hashes
in thread Intersect two hashes

Corion,

The perlfaq describes intersection of two arrays. I feel this is a better solution for intersecting arrays than what is mentioned in the faq.

However, I am looking to intersect hashes. What I am doing right now is :

foreach (keys %hash1){ $intersected_hash{$_} = $hash1{$_} if exists $hash2{$_}; }
Is there a better way to do this?

Replies are listed 'Best First'.
Re^3: Intersect two hashes
by Corion (Patriarch) on Jun 10, 2007 at 20:00 UTC

    I mentioned the FAQ because the only meaningful interpretation of "intersection" of two hashes is the intersection of their keys, which leads back to determining the intersection of two lists. I would code the loop a bit differently:

    my @intersection = grep { exists $hash2{$_} } keys %hash1; my %intersection; @intersection{ @intersection } = @hash1{ @intersection };

    Update: I made an error and had my %intersection where I should have assigned a hash slice instead. Fixed, thanks to ysth!

    Update 2: Fixed a syntax error - you can't declare a hash slice via my. Spotted again by ysth!

      you can't declare a hash slice via my
      You could have done
      @$_{ @intersection } = @hash1{ @intersection } for \my %intersection;
      but I don't know of any other one-statement way. Does Perl 6 provide a convenient syntax to declare a hash and initialize a slice of it in one swell foop?

      The task is slightly more interesting if you want to construct an intersection hash of the values that match. That may of course result in two keys for the same value in some cases. Maybe you'd want to key the intersection hash by the values from the original hash?

      I don't think OP tells us enough of the story really. A little XYish maybe?


      DWIM is Perl's answer to Gödel
Re^3: Intersect two hashes
by blazar (Canon) on Jun 10, 2007 at 21:14 UTC
    The perlfaq describes intersection of two arrays. I feel this is a better solution for intersecting arrays than what is mentioned in the faq.

    The faq is constantly updated to provide good answers but it is not perfect. More importantly, it gives example code for certain situations, that can be easily adapted to others.

    BTW: the link you inserted brought me to another incarnation of PM: this is annoying. To put it in a way that will be agnostic, just use [id://2461] or [id://2461|this], which will render respectively like How can I find the union/difference/intersection of two arrays? and this respectively.

    However, I am looking to intersect hashes.

    Hashes are functions: their keys can be regarded as sets. Sets have intersections, functions generally not. (But possibly in some particular branch of Mathematics.) Judging from your code and using intechangeably the word "hash" and the word "function", you want the restriction of the first hash to the intersection of its domain with that of the second one. The idiom in Perl for such a restriction is a slice which will work like thus: @hash1{LIST}. (A slice will also do more, but let's set that aside for the moment.) The given LIST can be simply built with grep. Thus:

    my %intersected_hash = @hash1{grep exists $hash2{$_}, keys %hash1};
      blazar, Thanks for the tips on posting. Also noted the difference between a set and a function. The solution you suggested works great. Thanks,