IRC Hacking

Purdy on 2005-09-07T13:24:16

So I was on #cgiapp (irc.perl.org) and Cees Hek taught me a few things, one involving lists, arrays and scalars.

Have you ever tried this? @a=('one','two','three'); $b = @a; print $b;

So what's the output? '3' ... I knew that and my world was safe & sheltered. Then Cees threw this one at me: $b = ('one','two','three');print $b;

What's that output? '3'? ... Nope, it's 'three', the last element of the list.

insert sound of head exploding

Before moving on, I think this is a good example of how such a truth of life can really alter your worldview. Not just in Perl, but when you learn something new like that, it really breaks your grip on "reality" and takes a moment (or two) to readjust and get a new grip. I encourage a good shake-up every once in a while.

Ok, so then I was head-coding while playing with Meredith (she's so cute), getting around a CSV file that I will need to import into a database and it has rows with ID #'s and then a column in a row for other ID #'s that are the same 'entity'. So I plan on consolidating them into my shiny new relational db. So I'll need something to determine if the ID # is the minimal # of the set - if so, it's a new 'entity' record. Otherwise, associate the new record w/ the minimal number.

So I'll have the ID # and a list of other ID #'s and I need to know if it's the smallest.

So then I said to myself ... what if I used that concept that Cees taught me w/ a reverse sort? Like: if ( $id_number == reverse sort @ids )

There are some context issues there that I couldn't (and still don't all that well) understand. Cees nailed it, though: if ( $id_number == @{[reverse sort @ids]}[0..$#ids] )

Pretty cool, huh? I call it the Hek-Purdy min(). Or maybe "a Hek of a Purdy-good min() function" (helps if you say that in a Southern accent ;)).

Now this is not very readable or maintainable, so I don't plan on world-wide deployment - just my import script ... for now. ;)

Peace,

Jason


Why so convoluted? Use a literal slice!

merlyn on 2005-09-07T13:46:49

So I'll have the ID # and a list of other ID #'s and I need to know if it's the smallest.
You went a very convoluted route to do this:
if ( $id_number == (sort @ids)[0] )
Learn about literal slice: (LIST)[INDICIES]. We document it in Learning Perl.

Re:Why so convoluted? Use a literal slice!

Purdy on 2005-09-07T13:56:44

*grin* - yeah, I know. I should have put a * next to "good" - I'm not endorsing that as THE way: TIMTOWTDI and all that. And your approach is definitely cleaner ... I was just thinking about how to incorporate what I learned about scalarizing a list.

Peace,

Jason

min()

ziggy on 2005-09-07T13:53:28

So I'll have the ID # and a list of other ID #'s and I need to know if it's the smallest.

That code is very confusing. Sorta like taking a flight from NY to LA by via Johannesburg and Perth. Why not just grab the smallest element of the list?

use List::Util qw(min);

if ( $id_number == min(@ids) )

If you needed to avoid List::Util for some odd reason, I don't know why you would sort a list, reverse it and take the last element (in a most convoluted fashion) when you could just:

if ( $id_number == (reverse sort @ids)[-1] )

Or even more clearly:

if ( $id_number == (sort @ids)[0] )

Re:min()

Purdy on 2005-09-07T14:04:04

*nod* - agreed. See prev. comment - I simply wanted to apply what Cees taught me about scalarizing a list.

Hmmm -- maybe this won't even see the light of day in my import script now. ;)

Peace,

Jason

Re:

Aristotle on 2005-09-08T12:11:07

I thought it was common knowledge that there is no such thing as a list in scalar context. :-)

The context issues are particularly important when you return things. my $foo = bar(); will produce a different result with a bar function that does return @arr; vs one that does return ( $baz1, $baz2, $baz3 ). This is even more insidious if you do something like return grep quux($_), @arr.

Always mind your context.

Your particular example, btw, besides all the issues already pointed out by others, should at least be written without that anonymous array in there:

if ( $id_number == ( reverse sort @ids )[ 0 .. $#ids ] ) {
    # ...
}

which then leads to the further simplifications ziggy pointed out.