Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

two dimensional array lookup

by dannoura (Pilgrim)
on Jul 17, 2003 at 03:52 UTC ( [id://275102]=perlquestion: print w/replies, xml ) Need Help??

dannoura has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I'm trying to look through a two dimensional array and indicate all repeating elements. I'm sure there is some clever way to do it with two lines of code, but I can't think of one.

If I have an array that looks like:

@all=(["what", "is", "the", "matrix"],["matrix", "reloaded", "is", "no", "good"]);

I'd like to have an array which looks like:

([0, 1, 0, 1], [1, 0, 1, 0, 0])

So that all matches are pointed out. What would be the best way to do this?

p.s. a simple but comprehensive explanation of the map function will also be appreciated.

Replies are listed 'Best First'.
Re: two dimensional array lookup
by simonm (Vicar) on Jul 17, 2003 at 04:32 UTC

    Two lines are indeed enough.

    # Build a hash of word counts foreach ( map @$_, @all ) { $words{$_} ++ } # Create a list of arrays showing repeats @out = map { [ map $words{$_} > 1 ? 1 : 0, @$_ ] } @all;

    With regards to map, I find it easiest to think of it as a rolled-up form of the common foreach ... push idiom:

    # List processing with foreach/push foreach ( @input ) { push @out, lc($_); } print @out; # Equivalent "rolled-up" map expression: print map { lc($_) } @input;
      ++ because It took me some time to figure out how your solution works.
Re: two dimensional array lookup
by sgifford (Prior) on Jul 17, 2003 at 04:35 UTC
    The most straightforward way to do what you want is to use a hash to keep track of the elements that already exist, then scan the hash to determine duplicates. Something like:
    #!/usr/bin/perl -w use strict; use vars qw(@all @dup); @all=(["what", "is", "the", "matrix"],["matrix", "reloaded", "is", "no +", "good"]); my(%h1,%h2); # for the two halves of your array grep { $h1{$_}=1 } @{$all[0]}; grep { $h2{$_}=1 } @{$all[1]}; @dup = ( [ map { $h2{$_} ? 1 : 0 } @{$all[0]} ], [ map { $h1{$_} ? 1 : 0 } @{$all[1]} ]); print '([', join(',',@{$dup[0]}), '], [', join(',',@{$dup[1]}), "])\n";
    Oh, and map executes a block of code for each element in the array, returning an array consisting of the return value from each block of code.
      I would write this
      grep { $h1{$_}=1 } @{$all[0]};
      like this
      grep { $h1{$_}=1; undef; } @{$all[0]};
      in order not to get all my elements from @{$all[0]} as a return value of grep.

      I even might write:

      @h1{@{$all[0]}}=(1) x @{$all[0]};
        Why use grep at all if you don't need a return value?
        $h1{$_}=1 for @{$all[0]};
Re: two dimensional array lookup
by tos (Deacon) on Jul 17, 2003 at 13:55 UTC
    when i saw simonms great solution i was ashamed of my own. But since it was a little trouble for me and because of TMTOWTDI here my approach.

    use strict; use warnings; use Data::Dumper; my @erg; my @all=(["what", "is", "the", "matrix"],["matrix", "reloaded", "is", +"no", "good"]); print "\n",Dumper(\@all); for (my $i = 0; $i < @{$all[0]}; $i++) { for (my $j = 0; $j < @{$all[1]}; $j++) { $erg[0][$i] ||= sprintf "%u", ($all[0][$i] eq $all[1][$j]); $erg[1][$j] ||= sprintf "%u", ($all[0][$i] eq $all[1][$j]); } } print "\n",Dumper(\@erg);
    greetings, tos

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://275102]
Approved by crouchingpenguin
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2024-04-18 12:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found