Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: Using hashes for set operations...

by jaredor (Curate)
on May 22, 2011 at 04:52 UTC ( #906114=note: print w/replies, xml ) Need Help??

in reply to Using hashes for set operations...

I don't know what underlying perl mechanics I'm potentially violating (update: I meant in generating union, everything else should be jake), but the following seems to work. There's no idea here that wasn't in your original post; in fact I referred to it frequently when writing this up.

#!/usr/bin/env perl use strict; use warnings; my @array1=(1..5); my @array2=(3..7); my (%union, %sdiff, %sd1, %sd2, %inter); @union{(@array1,@array2)} = (@array1,@array2); %sd1 = %sd2 = %inter = %union; delete @sd1{@array2}; delete @sd2{@array1}; %sdiff = (%sd1,%sd2); delete @inter{keys %sdiff}; print "array1: ", join (" ", @array1), "\n"; print "array2: ", join (" ", @array2), "\n"; print "union: ", join (" ", keys %union), "\n"; print "sdiff: ", join (" ", keys %sdiff), "\n"; print "inter: ", join (" ", keys %inter), "\n";

It felt like I was writing either haiku or APL, but I can't quite say which....

Replies are listed 'Best First'.
Re^2: Using hashes for set operations...
by LanX (Chancellor) on May 23, 2011 at 08:51 UTC
    Hmm interesting!

    I was sure that using De Morgan's laws would just relocate the problem and not solve it. (you're now only deleting hash-slices)

    But this relocation makes sense ... now it works for all cases where "undef" isn't allowed as part of an initial set. (undef deletes empty strings).

    But you shouldn't use print to inspect data structures:

    #!/usr/bin/env perl use strict; use warnings; use Data::Dump qw(pp); my @array1=(1..2,""); my @array2=(2..3,undef); my (%union, %sdiff, %sd1, %sd2, %inter); @union{(@array1,@array2)} = (@array1,@array2); %sd1 = %sd2 = %inter = %union; delete @sd1{@array2}; delete @sd2{@array1}; %sdiff = (%sd1,%sd2); delete @inter{keys %sdiff}; print "array1: ", pp(\@array1), "\n"; print "array2: ", pp(\@array2), "\n"; print "union: ", pp(\%union), "\n"; print "sdiff: ", pp(\%sdiff), "\n"; print "inter: ", pp(\%inter), "\n"; print "sd1: ", pp(\%sd1), "\n"; print "sd2: ", pp(\%sd2), "\n";


    Use of uninitialized value $array2[2] in hash slice at /home/lanx/B/PL +/PM/ line 12. Use of uninitialized value $array2[2] in delete at /home/lanx/B/PL/PM/ line 16. array1: [1, 2, ""] array2: [2, 3, undef] union: { "" => undef, 1 => 1, 2 => 2, 3 => 3 } sdiff: { 1 => 1, 3 => 3 } inter: { "" => undef, 2 => 2 } sd1: { 1 => 1 } sd2: { 3 => 3 }

    But while you found a mathematical solution, needing so many operations for an intersection is in practice a little disappointing ...

    Thanks anyway! :)

    Cheers Rolf

      Sir, to me "elegant" is equivalent to "mathematical"!

      (Even though I am a failed mathematician, it does sting a little that you felt the need to give me a link to De Morgan's laws.)

      True, I did treat this more as a little puzzle than a real world answer, but then what do you expect with only allowing the set operations, "union" and "subtraction"? As for that, you only get the union property as a side effect from hash key creation (which (I think) would not give even a squeak of protest if there were two key/value pairs with identical keys and different values, but by construction we avoid this issue).

      Although I've never used this behavior, apparently the delete function does return a list of keys values it's deleted, so delete(@A{keys B}) does return the intersection of A and B ... as well as an undef for every key value that was in B and not in A; so you're back to square 1 with ugly undefs in your answer. (Hence I still haven't used this behavior.) BTW, it just occurred to me that for the symmetric differences %sd1 and %sd2 don't have to be copies of the union, they only need to be the hash equivalents of @array1 and @array2, respectively.

      I love talking like a pedant, but in addition to this vice, I have to admit to a hypocrisy: I love using map and grep more, even to the point of using them for their side effects, which means a significant portion of my time in writing up my (few) posts on perlmonks is translating to while and for constructs. So I'm sincere when I say that your original post was elegant enough for me: Handling undefs in perl is just a fact of life, and if you can do it with just one swipe of the knife, then you are about as good as you're going to get without reformulating your approach.

      My last gratuitous squeak of protest is that print statements suffice if they work correctly for a code that is an illustration of a solution; in other words, it is not a data structure at that point so much as a formatted solution! (That being said, you've shamed me enough that I will try to start using Data::Dumper in my posts.)

      I've just gone through and removed all the smiley's from this post. So now I look smarter, but more crotchety. Anyone who reads this please note that I enjoy these kinds of "pure perl" puzzles and have enjoyed everyone's contribution to this query of LanX's. I spent years as a coder looking for good coders to critique my work with only modest success. Here at perlmonks you get high quality feedback quickly--and you still learn from the low quality feedback because you now have context in which to evaluate it. Good stuff, and thank you LanX.

        > apparently the delete function does return a list of keys it's deleted, so delete(@A{keys B}) does return the intersection of A and B ...

        Good observation! I forgot about this.... so one gets the difference and the intersection with one operation, thats brilliant.

        So a simple upgrade of delete with an extra switch to ignore undefs would give Perl a native primitive to handle set operations...

        And I enjoyed your post too, I'm still meditating about how to make use of your approach...

        > (Even though I am a failed mathematician, it does sting a little that you felt the need to give me a link to De Morgan's laws.)

        The link wasn't meant for you, believe me. :)

        I'm mathematician by training but not a native English speaker, so I need to elaborate my posts longer and stuff them with extra informations to avoid misunderstandings. (And the monastery is full of obsessed nitpickers...)

        Cheers Rolf

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://906114]
[marto]: when you work on the outside, for a client, you can make them aware of the stupids, but they don' t always listen :/
[Corion]: Yeah, you can lead them to water, but it's illegal to drown them...
[Discipulus]: Here my solution marto: create a win fake machine insied AD. do a micro fake partition foreach remote partition you wont to monit. put a web server that acept from data from remote systems and full fake partition as needed. fake partition are Mb. ;=)
[marto]: Discipulus yeah, the nuclear industry love fake machines sitting around on a controlled domain :P
[marto]: changing a typo on a website is often a great deal of paper work :P

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (10)
As of 2017-01-24 10:39 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (203 votes). Check out past polls.