Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

Trying to get fancy...

by Purdy (Hermit)
on Nov 28, 2001 at 20:09 UTC ( #128072=perlquestion: print w/replies, xml ) Need Help??

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

Ever since I learned you can put an EXPR as the first arg in grep, I've been going grep-crazy. I think I've hit a wall, though, in my ability and could use some guidance/help.

I have two arrays (@listA and @listB) which themselves contain references to arrays as each element. I want to get a list of elements in @listB that aren't in @listA, according to the first element of the 'embedded' array (which is there by reference).

# this isn't really the assignment, but showing an example $listA[0] = ['1','foo','bar']; $listB[0] = ['1','bar','baz']; # these prints fine print 'First record from @listA: ' . (@{$listA[0]})[0] . "\n"; print 'First record from @listB: ' . (@{$listB[0]})[0] . "\n"; # We first want to get a list of records # in B that aren't in A my ( $a, $b ); @listToExpire = grep ( ($b = (@{$_})[0] && grep( ($a = (@{$_})[0] && $b != $a), @listA )), @listB );

When I step through the debugger, $a & $b never get defined. Why?

As always, thanks in advance!


Replies are listed 'Best First'.
Re: Trying to get fancy...
by dragonchild (Archbishop) on Nov 28, 2001 at 20:20 UTC
    *blink* *blinkblink*

    Wow. That takes my vote for most obfuscated-but-didn't-mean-to code of the day.

    First, a rewrite of the code, so we can start to see what's going on:

    $listA[0] = [qw(1 foo bar)]; $listB[0] = [qw(1 bar baz)]; print "First record from \@listA: $listA[0][0]\n"; @listToExpire = grep { } @listB;
    The {} say that you need to do some stuff on each element of @listB. However, your code is of the form grep ( @listB ); Are you sure this is what you want?

    Update: Try the following:

    my @listToExpire = grep { my $a = $_; (grep /$a/, @listA) ? () : ($a); + } @listB;
    Interestingly enough, you can substitute map for the grep. Of course, I wrote it initially with map, cause that's how I think. TMTOWTDI.

    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Yep - for each element in @listB, I want to pry out the first element, assign it to $b and then do another nested grep on all elements of @listA and see if $b is in there. If it isn't, then I want it assigned to the overall @listToExpire array.

      I rewrote the line to use the { }'s:

      @listToExpire = grep { $b = (@{$_})[0] && grep { $a = (@{$_})[0] && $b != $a } @listA } @listB;

      Still the same result:
      Use of uninitialized value in numeric ne (!=) at ./ line 62.
      Use of uninitialized value in numeric ne (!=) at ./ line 62.

      I know I could do it in a more readable foreach loop (or a lookup hash), but thought I would take on a challenge, instead. :)


      Update: I got it to work! Thanks, dragonchild! Here's the final version:

      @listToExpire = grep { $b = (@{$_})[0]; grep { $a = (@{$_})[0]; $b != +$a } @listA } @listB;

      It was those '&&''s ... I still don't understand them outside of the typical boolean EXPR. Need to grok that & the 'and|or' stuff, too.

        Though readability may not be a high priority for you in this excercise, consider changing this:


        to this

Re: Trying to get fancy...
by AidanLee (Chaplain) on Nov 28, 2001 at 20:24 UTC

    untested, but this should work:

    my %hash; @hash{ map { $_->[0] } @listA } = ( 1 ) x @listA; grep{ 1 unless defined $hash{$_->[0]} } @listB;

    looking up 'intersection' in the search box comes up with some useful results

Re: Trying to get fancy...
by jlongino (Parson) on Nov 28, 2001 at 22:38 UTC
    Good and interesting post Purdy! I've been playing with the code and following the evolution of the replies. I've not used LOLs before and found the array syntax(es) not very intuitive. I borrowed DragonChilds array initialization technique and used a map/grep strategy similar to AidanLees. For some reason it is easier for me to grasp  @{$listA[0]} representation than to break it down further to  $_->[0] constructs. Maybe more practice (and learning some OOP) on my part will help.
    use strict; my (@listA, @listB); $listA[0] = [qw(1 foo bar)]; $listB[0] = [qw(1 bar baz)]; my %hash = map { $_ => 1 } @{$listA[0]}; my @c = grep {! exists $hash{$_}} @{$listB[0]}; print "$_\n" foreach (@c);

    Update: changed  @listX[0] as per seanbos reply. Thanks seanbo, I originally had it right but forgot to change it back after an unfruitful experiment. Should've used -w.

      < nit > If you run this with warnings, it will complain about:
      @listA[0] = [qw(1 foo bar)]; @listB[0] = [qw(1 bar baz)];

      /methinks you meant:
      $listA[0] = [qw(1 foo bar)]; $listB[0] = [qw(1 bar baz)];

      < /nit > Either way, I guess it runs...

      perl -e 'print reverse qw/o b n a e s/;'

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://128072]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (10)
As of 2019-12-16 13:31 GMT
Find Nodes?
    Voting Booth?

    No recent polls found