[30976] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 2221 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Thu Feb 19 14:09:51 2009

Date: Thu, 19 Feb 2009 11:09:14 -0800 (PST)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Thu, 19 Feb 2009     Volume: 11 Number: 2221

Today's topics:
        [DGBI] oops, obviously I've missed something (was: rege <whynot@pozharski.name>
    Re: [DGBI] oops, obviously I've missed something (was:  sln@netherlands.com
    Re: extracting values from vmstat output <tadmc@seesig.invalid>
    Re: extracting values from vmstat output <uri@stemsystems.com>
    Re: extracting values from vmstat output <tim@burlyhost.com>
    Re: Net::SSH2 scp_put not working! <schaitan@gmail.com>
    Re: Net::SSH2 scp_put not working! <tim@burlyhost.com>
    Re: Net::SSH2 scp_put not working! <schaitan@gmail.com>
    Re: programming by evolution? <albert@spenarnc.xs4all.nl>
        Sorting based on existence of keys <burner+usenet@imf.au.dk>
    Re: Sorting based on existence of keys <peter@makholm.net>
    Re: Sorting based on existence of keys <jurgenex@hotmail.com>
    Re: Sorting based on existence of keys xhoster@gmail.com
    Re: Sorting based on existence of keys <uri@stemsystems.com>
    Re: Sorting based on existence of keys <jimsgibson@gmail.com>
        Sorting hash of hashes <justin.0810@purestblue.com>
    Re: Sorting hash of hashes <justin.0810@purestblue.com>
    Re: Sorting hash of hashes (Greg Bacon)
    Re: Sorting hash of hashes xhoster@gmail.com
    Re: Sorting hash of hashes (Greg Bacon)
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Thu, 19 Feb 2009 05:08:53 +0200
From: Eric Pozharski <whynot@pozharski.name>
Subject: [DGBI] oops, obviously I've missed something (was: regexp or array?)
Message-Id: <slrngppjbh.oqh.whynot@orphan.zombinet>

On 2009-02-18, Peter Makholm <peter@makholm.net> wrote:
> End of Road <joblo@cretin.fr> writes:
>
>> Using regular expressions
>>
>> $strs = 'str1|str2|str3";
>> if ($str =~ /strs/)
>>   ...
>>
>> Or using an array
>>
>> @strs = qw/str1,str2, str3/;
>> foreach (@strs) {
>>    if ($_[0] =~ /$_/)
>>        ...
>
> Better use an array of precompiled regexpes:
>
> my @regexp = map { qr/$_/ } qw(foo bar baz);
>
> if( grep { $_[0] =~ $_ } @regexp ) {
>
>   ...
>
> }

perl -wle '
use Benchmark qw|cmpthese timethese|;
my @arg = qw{ aa cc ee ff };
my $x = qr{a|b|c};
my $y = q{a|b|c};
cmpthese timethese -10, {
        pure => sub { m{a|b|c} foreach @arg },
        prec => sub { m{$x} foreach @arg },
        expl => sub { $_ =~ $x foreach @arg },
        alt => sub { $x foreach @arg },
        eval => sub { m{$y} foreach @arg },
};
'
Useless use of private variable in void context at -e line 10.
Benchmark: 
running
 alt, eval, expl, prec, pure
 for at least 10 CPU seconds
 ...

       alt: 12 wallclock secs (10.38 usr +  0.02 sys = 10.40 CPU) @ 267620.77/s (n=2783256)

      eval: 11 wallclock secs (10.10 usr +  0.04 sys = 10.14 CPU) @ 57220.81/s (n=580219)

      expl: 11 wallclock secs (10.52 usr +  0.04 sys = 10.56 CPU) @ 37743.47/s (n=398571)

      prec: 11 wallclock secs (10.56 usr +  0.02 sys = 10.58 CPU) @ 38041.49/s (n=402479)

      pure: 11 wallclock secs (10.36 usr +  0.02 sys = 10.38 CPU) @ 61972.35/s (n=643273)

         Rate expl prec eval pure  alt
expl  37743/s   --  -1% -34% -39% -86%
prec  38041/s   1%   -- -34% -39% -86%
eval  57221/s  52%  50%   --  -8% -79%
pure  61972/s  64%  63%   8%   -- -77%
alt  267621/s 609% 603% 368% 332%   --

I've checked 4 times, C<expl> and C<prec> flip-flops, while
C<eval> and C<pure> are stable.  What I've missed this time?

C<alt> seems to be a *way* fast, right?  Left as an excersise for curious
readers.  (spoiler, since rot13 is letter only, 100 empty lines below)





































































































perl -wle '
$x = qr{(?{ print 1 })};
@y = qr{ a b c };
$x foreach (@y)'
Useless use of a variable in void context at -e line 4.

*CUT*

-- 
Torvalds' goal for Linux is very simple: World Domination
Stallman's goal for GNU is even simpler: Freedom


------------------------------

Date: Thu, 19 Feb 2009 18:45:46 GMT
From: sln@netherlands.com
Subject: Re: [DGBI] oops, obviously I've missed something (was: regexp or array?)
Message-Id: <ie9rp4p8bm8q3ujd7li8nu3bv3hudlajss@4ax.com>

On Thu, 19 Feb 2009 05:08:53 +0200, Eric Pozharski <whynot@pozharski.name> wrote:

>On 2009-02-18, Peter Makholm <peter@makholm.net> wrote:
>> End of Road <joblo@cretin.fr> writes:
>>
>>> Using regular expressions
>>>
>>> $strs = 'str1|str2|str3";
>>> if ($str =~ /strs/)
>>>   ...
>>>
>>> Or using an array
>>>
>>> @strs = qw/str1,str2, str3/;
>>> foreach (@strs) {
>>>    if ($_[0] =~ /$_/)
>>>        ...
[snip]

>perl -wle '
>use Benchmark qw|cmpthese timethese|;
>my @arg = qw{ aa cc ee ff };
>my $x = qr{a|b|c};
>my $y = q{a|b|c};
>cmpthese timethese -10, {
>        pure => sub { m{a|b|c} foreach @arg },
>        prec => sub { m{$x} foreach @arg },
>        expl => sub { $_ =~ $x foreach @arg },
>        alt => sub { $x foreach @arg },
                      ^^
Doesen't do anything, there is no operator to tell the compiler
what to do with it. Its exactly the same as foreach (@arg) {};

>        eval => sub { m{$y} foreach @arg },
>};
>'
>Useless use of private variable in void context at -e line 10.
>Benchmark: 
>running
> alt, eval, expl, prec, pure
> for at least 10 CPU seconds
[snip]
>pure  61972/s  64%  63%   8%   -- -77%
>alt  267621/s 609% 603% 368% 332%   --
>
>I've checked 4 times, C<expl> and C<prec> flip-flops, while
>C<eval> and C<pure> are stable.  What I've missed this time?
>

What does this benchmark? Its not a contrast between a single regex
vs an array of regex. The fact is that qr// is just a suggestion to the
compiler. (?-xism:a|b|c) is just a longer string to be interpred every time
the sub gets called.

>C<alt> seems to be a *way* fast, right?  Left as an excersise for curious
>readers.  (spoiler, since rot13 is letter only, 100 empty lines below)
>
[snip]
>
>perl -wle '
>$x = qr{(?{ print 1 })};
>@y = qr{ a b c };
>$x foreach (@y)'
>Useless use of a variable in void context at -e line 4.
>
Still doesen't do anything, there is no operator for $x.

>*CUT*

alt3 => sub { $x foreach (@arg); },
alt4 => sub { foreach (@arg){}; },
alt5 => sub { $_ =~ $x foreach (@arg); },
alt6 => sub { /$x/ foreach (@arg); },

         Rate alt5 alt6 alt3 alt4
alt5 272315/s   --  -2% -64% -65%
alt6 278751/s   2%   -- -63% -64%
alt3 760285/s 179% 173%   --  -2%
alt4 779012/s 186% 179%   2%   --

-sln



------------------------------

Date: Thu, 19 Feb 2009 08:01:00 -0600
From: Tad J McClellan <tadmc@seesig.invalid>
Subject: Re: extracting values from vmstat output
Message-Id: <slrngpqpgs.q58.tadmc@tadmc30.sbcglobal.net>

alfonsobaldaserra <alfonso.baldaserra@gmail.com> wrote:


[ attribution missing... ]


>>     my($memory) = $vmstat =~ /(\d+) memory pages/;


> why are you using
> $memory and $free in list context?


Because it DWIMs more clearly (IMO) than the alternatives.

What I Mean is usually: 

    set $memory to a capture if matched, set it to undef if unmatched.

That's what my list-context approach above does.

The good, but less clear and more wordy, approach to it is:

   my $memory;
   if ( $vmstat =~ /(\d+) memory pages/ ) {
       $memory = $1;
   }

or

   my $memory;
   $memory = $1 if $vmstat =~ /(\d+) memory pages/;


The construct I am specifically avoiding is:

   my $memory = $1 if $vmstat =~ /(\d+) memory pages/;

to avoid the dragons referred to in the "Statement Modifiers"
section of perlsyn.pod:


    B<NOTE:> The behaviour of a C<my> statement modified with a statement
    modifier conditional or loop construct (e.g. C<my $x if ...>) is
    B<undefined>.  The value of the C<my> variable may be C<undef>, any
    previously assigned value, or possibly anything else.  Don't rely on
    it.  Future versions of perl might do something different from the
    version of perl you try it out on.  Here be dragons.


-- 
Tad McClellan
email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"


------------------------------

Date: Thu, 19 Feb 2009 11:11:18 -0500
From: Uri Guttman <uri@stemsystems.com>
Subject: Re: extracting values from vmstat output
Message-Id: <x7ab8ixv89.fsf@mail.sysarch.com>

>>>>> "TJM" == Tad J McClellan <tadmc@seesig.invalid> writes:


  TJM>    my $memory;
  TJM>    $memory = $1 if $vmstat =~ /(\d+) memory pages/;


  TJM> The construct I am specifically avoiding is:

  TJM>    my $memory = $1 if $vmstat =~ /(\d+) memory pages/;

  TJM> to avoid the dragons referred to in the "Statement Modifiers"
  TJM> section of perlsyn.pod:

so use the conditional expression:

	my $memory = $vmstat =~ /(\d+) memory pages/ ? $1 : undef ;

but the list context method is fine IMO.

and i still prefer the grabbing of all the values into a hash in one
statement. declaring a lexical for each of many values is bad news. we
just had a thread on someone who did that (not parsed out, just declared
too many vars).

uri


-- 
Uri Guttman  ------  uri@stemsystems.com  --------  http://www.sysarch.com --
-----  Perl Code Review , Architecture, Development, Training, Support ------
--------- Free Perl Training --- http://perlhunter.com/college.html ---------
---------  Gourmet Hot Cocoa Mix  ----  http://bestfriendscocoa.com ---------


------------------------------

Date: Thu, 19 Feb 2009 09:05:55 -0800
From: Tim Greer <tim@burlyhost.com>
Subject: Re: extracting values from vmstat output
Message-Id: <Tjgnl.13436$lk5.10457@newsfe13.iad>

Sherm Pendley wrote:

> Tim Greer <tim@burlyhost.com> writes:
> 
>> alfonsobaldaserra wrote:
>>
>>>> # untested
>>>> my $vmstat = qx/vmstat -v/;
>>>> my($memory) = $vmstat =~ /(\d+) memory pages/;
>>>> my($free)   = $vmstat =~ /(\d+) free pages/;
>>>>
>>> 
>>> your untested code turned out to be perfect. i got what i wanted.
>>> thank you.
>>> 
>>> but i have one question could you please answer? why are you using
>>> $memory and $free in list context? i tried running it as scalar and
>>> the output was 1 but in list context it gives correct value.
>>
>> One method is the result of the "test" of that condition (matching),
>> while the other assigns the value returned (not true or false).  It's
>> not that it's in a list context
> 
> Context is *exactly* what makes that difference. In scalar context,
> the =~ operator returns true/false, and in list context it returns a
> list of the matched subexpressions.
> 
> See 'perldoc perlop' and 'perldoc perlre' for details.
> 
> sherm--
> 

You cut out the part that said "in other words".  I meant that it's not
just the list context, but how it's used (the behavior in list context)
and that it depends on the particular operator (just like the docs
say)... just like the OP observed and just like I said above (returning
true or false, or the return value, depending).  In "other words", they
needed to know that if it didn't capture the desired value in
parethesis on the right, it would give them a different result, too. 
Perhaps it was poorly explained by not elaborating on what I meant, but
it was not a disagreement with anything you've said above or in the
docs themselves.
-- 
Tim Greer, CEO/Founder/CTO, BurlyHost.com, Inc.
Shared Hosting, Reseller Hosting, Dedicated & Semi-Dedicated servers
and Custom Hosting.  24/7 support, 30 day guarantee, secure servers.
Industry's most experienced staff! -- Web Hosting With Muscle!


------------------------------

Date: Thu, 19 Feb 2009 05:59:42 -0800 (PST)
From: Krishna Chaitanya <schaitan@gmail.com>
Subject: Re: Net::SSH2 scp_put not working!
Message-Id: <2ee58238-c6d5-4ede-8b49-beb3c01fe19d@o2g2000prl.googlegroups.com>

Hmm...I've never done anything of this sort, so pls. bear with my
ignorance. Let's say 10.0.1.174 is the remote machine and my machine
where I'm working is 10.0.75.202. I've used tcpdump in this way:

Opened 2 parallel PuTTY sessions to 10.0.1.174 and executed these :

Putty session A - "tcpdump -vvv src host 10.0.75.202"
Putty session B - "tcpdump -vvv dst host 10.0.75.202"

Session A shows 13 packets and Session B shows 12.....frankly I have
no clue of what's going on here.....I've searched google on how to
interpret tcpdump headers but it's not helping much to decipher why
blocking I/O is causing the problem here.... :(


------------------------------

Date: Thu, 19 Feb 2009 09:10:37 -0800
From: Tim Greer <tim@burlyhost.com>
Subject: Re: Net::SSH2 scp_put not working!
Message-Id: <hognl.13458$lk5.6187@newsfe13.iad>

Krishna Chaitanya wrote:

> Hmm...I've never done anything of this sort, so pls. bear with my
> ignorance. Let's say 10.0.1.174 is the remote machine and my machine
> where I'm working is 10.0.75.202. I've used tcpdump in this way:
> 
> Opened 2 parallel PuTTY sessions to 10.0.1.174 and executed these :
> 
> Putty session A - "tcpdump -vvv src host 10.0.75.202"
> Putty session B - "tcpdump -vvv dst host 10.0.75.202"
> 
> Session A shows 13 packets and Session B shows 12.....frankly I have
> no clue of what's going on here.....I've searched google on how to
> interpret tcpdump headers but it's not helping much to decipher why
> blocking I/O is causing the problem here.... :(

I'm curious, out of all of the testing with the script, have you
thoroughly tested SSH/scp over the network/systems in such a way that
it would indicate a problem with the connections or transfer process
before you start getting into the gory details of the script?  Have you
considered using SSH keys rather than the login?  How many files are
you moving, how often, and how large are they potentially?
-- 
Tim Greer, CEO/Founder/CTO, BurlyHost.com, Inc.
Shared Hosting, Reseller Hosting, Dedicated & Semi-Dedicated servers
and Custom Hosting.  24/7 support, 30 day guarantee, secure servers.
Industry's most experienced staff! -- Web Hosting With Muscle!


------------------------------

Date: Thu, 19 Feb 2009 10:50:47 -0800 (PST)
From: Krishna Chaitanya <schaitan@gmail.com>
Subject: Re: Net::SSH2 scp_put not working!
Message-Id: <a0f48b2d-72ca-48f0-bd5f-930bd546d557@p2g2000prf.googlegroups.com>

Hi Tim,

SSH/SCP work very smoothly at least in my test bed (don't have access
yet to the customer's network). At least, they work smoothly when I
type the commands at the prompt. But they don't when I use synchronous
I/O as discussed above.

SSH key exchange is not permitted by the customer in his network. I am
expected to host my program on a Linux box and execute it to copy a
set of files (about 300 MB in total) from there to each machine (list
of IP addresses and their passwords is provided up front). After
copying those files, I will have to execute certain programs on each
machine and log the output to a central directory. With Net::SSH2,
since it is smart enough (?) to expect and react to SSH challenges, I
had a feeling I wouldn't really need SSH key exchange.


------------------------------

Date: 19 Feb 2009 18:56:42 GMT
From: Albert van der Horst <albert@spenarnc.xs4all.nl>
Subject: Re: programming by evolution?
Message-Id: <kfbtyi.45w@spenarnc.xs4all.nl>

In article <03db1c69-828a-4961-914d-62fe10ed88fb@w39g2000prb.googlegroups.com>,
Xah Lee  <xahlee@gmail.com> wrote:
<SNIP>
>
>Pascal Constanza wrote:
>> Yes. There are actually complete software development methodologies
>> built around these ideas. Google for "extreme programming" and "agile
>> software methodologies".
>
>Pascal Constanza is a Common Lisp fanatic. Note here, that eXtreme
>Programing is one of the snake oil, that ran like rampant wild fire in
>the industry around 2002, with many books published on it on the
>supposed motherfucking hip Software Engineering practices, but today
>you don't hear much of it. I haven't looked at =E2=80=9CAgile programing=E2=
>=80=9D
>agile my ass, but it is probably a waste of time.
>
>... what society overwhelmingly asks for is snake oil. Of course, the
>snake oil has the most impressive names =E2=80=94otherwise you would be
>selling nothing=E2=80=94 like =E2=80=9CStructured Analysis and Design=E2=80=
>=9D, =E2=80=9CSoftware
>Engineering=E2=80=9D, =E2=80=9CMaturity Models=E2=80=9D, =E2=80=9CManagemen=
>t Information Systems=E2=80=9D,
>=E2=80=9CIntegrated Project Support Environments=E2=80=9D =E2=80=9CObject O=
>rientation=E2=80=9D and
>=E2=80=9CBusiness Process Re-engineering=E2=80=9D (the latter three being k=
>nown as
>IPSE, OO and BPR, respectively).=E2=80=9D =E2=80=94 Edsger W Dijkstra (1930=
>-2002), in
>EWD 1175: The strengths of the academic enterprise.
>

A couple of weeks ago, a collegue of mine held a lecture about
a company where he is hired,
building paper-folding and envelope-handling machines.
(We are hired hands).
Real time, and real time simulators. Full regression tests
after each change. Agile scrum all the way down.

It looks impressive especially from where I stand. ( Formal procedures that
take 6 months, and bad fixes because approved changes were no
good after all.)

So not dead by a margin, and less snake oil than most methodologies
I know of.

>  Xah

Groetjes Albert

--
-- 
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst



------------------------------

Date: Thu, 19 Feb 2009 14:28:16 +0100
From: Rasmus Villemoes <burner+usenet@imf.au.dk>
Subject: Sorting based on existence of keys
Message-Id: <u0ltz6qzhcf.fsf@orc10.imf.au.dk>

Hi experts

Say I have an array @ks containing some strings which may or may not
exist as keys in a hash %h. How do I sort @ks such that the
non-existent keys come last (in any order), while the existing keys
are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
really the property of the values I'll sort by, but that's not
important).

my @ks = qw(two three one four);
my %h = ( one => 1,
	  three => 333 );

for (sort { exists $h{$b} cmp exists $h{$a} ||
            length $h{$a} <=> length $h{$b}} @ks) { print "$_\n" }


This produces the intended result, but under "use warnings;" one also
gets the expected warnings when $h{two} and $h{four} are compared in
the second line. Is there some smarter way to do this? (Also, I don't
know if cmp is the right tool for comparing boolean values).

-- 
Rasmus Villemoes
<http://rasmusvillemoes.dk/>


------------------------------

Date: Thu, 19 Feb 2009 14:42:40 +0100
From: Peter Makholm <peter@makholm.net>
Subject: Re: Sorting based on existence of keys
Message-Id: <87y6w28rvz.fsf@vps1.hacking.dk>

Rasmus Villemoes <burner+usenet@imf.au.dk> writes:

> Say I have an array @ks containing some strings which may or may not
> exist as keys in a hash %h. How do I sort @ks such that the
> non-existent keys come last (in any order), while the existing keys
> are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
> really the property of the values I'll sort by, but that's not
> important).

My first idea would be to split the array in the two parts, sort each
of them and then concatenate them:

    for $key ( @ks ) {
        if (exists %h{$key} ) {
            push @existing, $key;
        } else { 
            push @nonexisting, $key;
    }
    @existing = sort { ... } @existing;

    for ( @existing, @nonexisting ) {
        ... 
    }

It might be a bit more effective to write an insert function to
replace the first push and by that eliminate the sorting.

It might enhance you job security to replace the loop with

    push @{ exists $h{$_} ? \@exists : \@nonexists }, $_
        for @ks;

//Makholm



------------------------------

Date: Thu, 19 Feb 2009 07:33:25 -0800
From: Jürgen Exner <jurgenex@hotmail.com>
Subject: Re: Sorting based on existence of keys
Message-Id: <hjuqp45gm1p04o0k81pdpd8ctl1rglhs5r@4ax.com>

Rasmus Villemoes <burner+usenet@imf.au.dk> wrote:

>Say I have an array @ks containing some strings which may or may not
>exist as keys in a hash %h. How do I sort @ks such that the
>non-existent keys come last (in any order), while the existing keys
>are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
>really the property of the values I'll sort by, but that's not
>important).

There are four different cases you have to consider in your custom
compare function:

$h{$a} and $h{$b} exist  ===>  length($h{$a}) <=> length($h{$a}) 
$h{$a} exists but $h{$b} doesn't  ===> -1
$h{$a} does't exist but $h{$b} does  ===> 1
Neither $h{$a} nor $h{$b} exists  ===>  0

jue  


------------------------------

Date: 19 Feb 2009 17:13:48 GMT
From: xhoster@gmail.com
Subject: Re: Sorting based on existence of keys
Message-Id: <20090219121243.863$hh@newsreader.com>

Rasmus Villemoes <burner+usenet@imf.au.dk> wrote:
> Hi experts
>
> Say I have an array @ks containing some strings which may or may not
> exist as keys in a hash %h. How do I sort @ks such that the
> non-existent keys come last (in any order), while the existing keys
> are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
> really the property of the values I'll sort by, but that's not
> important).
>
> my @ks = qw(two three one four);
> my %h = ( one => 1,
>           three => 333 );
>
> for (sort { exists $h{$b} cmp exists $h{$a} ||
>             length $h{$a} <=> length $h{$b}} @ks) { print "$_\n" }
>
> This produces the intended result, but under "use warnings;" one also
> gets the expected warnings when $h{two} and $h{four} are compared in
> the second line.

You could turn off the uninitialized warning for that block.

> Is there some smarter way to do this?

If you don't want to turn off the warning, you could detect when both are
nonexistent and short circuit on that.  And since we already know their
existence status is equal (otherwise we would have short-circuited on the
previous op), then we really only need to detect if one of them is
nonexistent.

for (sort { exists $h{$b} cmp exists $h{$a} ||
            exists $h{$b} &&
            length $h{$a} <=> length $h{$b}} @ks) { print "$_\n" }


> (Also, I don't
> know if cmp is the right tool for comparing boolean values).

It seems to do what ought to be done, so in my book that makes it the right
tool for the job.  I really doubt that future versions of Perl5 is going to
change the representations of true and false in a way that the outcome of
cmp is going to be different than it currently is.  You could also use <=>
to get the same outcome, because the special true value is greater than the
special false value both stringly ('' lt '1') and numerically (0 < 1)

Xho

-- 
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.


------------------------------

Date: Thu, 19 Feb 2009 13:01:00 -0500
From: Uri Guttman <uri@stemsystems.com>
Subject: Re: Sorting based on existence of keys
Message-Id: <x7prhewbkz.fsf@mail.sysarch.com>

>>>>> "JE" == Jürgen Exner <jurgenex@hotmail.com> writes:

  JE> Rasmus Villemoes <burner+usenet@imf.au.dk> wrote:
  >> Say I have an array @ks containing some strings which may or may not
  >> exist as keys in a hash %h. How do I sort @ks such that the
  >> non-existent keys come last (in any order), while the existing keys
  >> are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
  >> really the property of the values I'll sort by, but that's not
  >> important).

  JE> There are four different cases you have to consider in your custom
  JE> compare function:

  JE> $h{$a} and $h{$b} exist  ===>  length($h{$a}) <=> length($h{$a}) 
  JE> $h{$a} exists but $h{$b} doesn't  ===> -1
  JE> $h{$a} does't exist but $h{$b} does  ===> 1
  JE> Neither $h{$a} nor $h{$b} exists  ===>  0

this is why doing a prefilter on the sort keys makes life much
simpler. then you only have 1 real case to worry about - whether a key
exists or not. you can replace a non-existant key with a fake one that
always sorts higher than normal keys. this can be done in an ST or in
the key extraction code in Sort::Maker. i leave how to do that as an
exercise but it is much simpler than all the double sided checking you
propose.

uri

-- 
Uri Guttman  ------  uri@stemsystems.com  --------  http://www.sysarch.com --
-----  Perl Code Review , Architecture, Development, Training, Support ------
--------- Free Perl Training --- http://perlhunter.com/college.html ---------
---------  Gourmet Hot Cocoa Mix  ----  http://bestfriendscocoa.com ---------


------------------------------

Date: Thu, 19 Feb 2009 10:54:33 -0800
From: Jim Gibson <jimsgibson@gmail.com>
Subject: Re: Sorting based on existence of keys
Message-Id: <190220091054334998%jimsgibson@gmail.com>

In article <u0ltz6qzhcf.fsf@orc10.imf.au.dk>, Rasmus Villemoes
<burner+usenet@imf.au.dk> wrote:

> Hi experts
> 
> Say I have an array @ks containing some strings which may or may not
> exist as keys in a hash %h. How do I sort @ks such that the
> non-existent keys come last (in any order), while the existing keys
> are sorted using, say, length($h{$a}) <=> length($h{$a}) (that is not
> really the property of the values I'll sort by, but that's not
> important).
> 
> my @ks = qw(two three one four);
> my %h = ( one => 1,
>     three => 333 );
> 
> for (sort { exists $h{$b} cmp exists $h{$a} ||
>             length $h{$a} <=> length $h{$b}} @ks) { print "$_\n" }
> 
> 
> This produces the intended result, but under "use warnings;" one also
> gets the expected warnings when $h{two} and $h{four} are compared in
> the second line. Is there some smarter way to do this? (Also, I don't
> know if cmp is the right tool for comparing boolean values).

I would use grep:

#!/usr/bin/perl
use strict;
use warnings;

my @ks = qw(two three one four);
my %h = ( one => 1, three => 333 );

my @sorted = ( 
  (sort {length $h{$a} <=> length $h{$b}} grep {exists $h{$_}} @ks),
  (grep {!exists $h{$_}} @ks)
);

print "Keys: @sorted\n";

__OUTPUT__

Keys: one three two four

-- 
Jim Gibson


------------------------------

Date: Thu, 19 Feb 2009 14:37:33 -0000
From: Justin C <justin.0810@purestblue.com>
Subject: Sorting hash of hashes
Message-Id: <45e5.499d6ead.38ef2@zem>

Here's how my hash looks:

$hashes{$report}{$line}{$colNumber}

So, in %hashes, is data from several reports, grouped by report, then
line (well, stock code, which is the first field on the line), the
column number. Here is a little of the output of Data::Dumper:

$VAR1 = 'types';
$VAR2 = {
          'BE' => 1
        };
$VAR3 = 'stk1324r2';
$VAR4 = {
          'BE/COF/DRAGON' => {
                               '8' => '0',
                               '6' => '0',
                               '4' => 'E',
                               '3' => '1',
                               '7' => '2',
                               '9' => '2',
                               '2' => 'CRADLE OF FILTH dragon WEB BELT',
                               '5' => '2'
                             },
          'BE/MOT/WARPIG' => {
                               '8' => '0',
                               '6' => '0',
                               '4' => 'E',
                               '3' => '1',
                               '7' => '125',
                               '9' => '125',
                               '2' => 'MOTORHEAD warpig BADGEBUCKLE BELT',
                               '5' => '125'
                             },

I want to output the lines sorted asciibetically based on column 2, in
the above examples that'd be CRADLE OF FILTH..., and MOTORHEAD...

I'd like to provided an example of what I've tried, but the only idea
I've had is to extract the column 2 entries into an array, and then sort
the array and use it in a foreach loop, but then I've got to find a way
of accessing the hash from a value, and not a key (I can't use the
description as my key because there will be some sized items which will
have a different code, but identical description, so the code has to
stay as the key).

Thank you for any help you can give with this.

	Justin.

-- 
Justin C, by the sea.


------------------------------

Date: Thu, 19 Feb 2009 16:09:10 -0000
From: Justin C <justin.0810@purestblue.com>
Subject: Re: Sorting hash of hashes
Message-Id: <5310.499d8426.a787b@zem>

On 2009-02-19, Justin C <justin.0810@purestblue.com> wrote:
> Here's how my hash looks:
>
> $hashes{$report}{$line}{$colNumber}
>
> So, in %hashes, is data from several reports, grouped by report, then
> line (well, stock code, which is the first field on the line), the
> column number. Here is a little of the output of Data::Dumper:
>
> $VAR1 = 'types';
> $VAR2 = {
>           'BE' => 1
>         };
> $VAR3 = 'stk1324r2';
> $VAR4 = {
>           'BE/COF/DRAGON' => {
>                                '8' => '0',
>                                '6' => '0',
>                                '4' => 'E',
>                                '3' => '1',
>                                '7' => '2',
>                                '9' => '2',
>                                '2' => 'CRADLE OF FILTH dragon WEB BELT',
>                                '5' => '2'
>                              },
>           'BE/MOT/WARPIG' => {
>                                '8' => '0',
>                                '6' => '0',
>                                '4' => 'E',
>                                '3' => '1',
>                                '7' => '125',
>                                '9' => '125',
>                                '2' => 'MOTORHEAD warpig BADGEBUCKLE BELT',
>                                '5' => '125'
>                              },
>
> I want to output the lines sorted asciibetically based on column 2, in
> the above examples that'd be CRADLE OF FILTH..., and MOTORHEAD...
>
> I'd like to provided an example of what I've tried, but the only idea
> I've had is to extract the column 2 entries into an array, and then sort
> the array and use it in a foreach loop, but then I've got to find a way
> of accessing the hash from a value, and not a key (I can't use the
> description as my key because there will be some sized items which will
> have a different code, but identical description, so the code has to
> stay as the key).

I've looked further at this and found a "sort hash by value" example.
Looking at it, I remember it from the Llama. I can see how to apply that
to a simple hash, "@sorted = sort { $hash{$a} cmp $hash{$b} } keys
%hash". But am not sure how to make $hashes{$report}{$item}{2} fit.

What I've got is:

my @sorted = sort byAlpha ( keys ( %{$hashes{$report}} ) );

sub byAlpha {
    $hashes{$report}{$item}{2}{a} cmp $hashes{$report}{$item}{2}{a};
}

And, of course, $report is not passed to the sub and is therefore undef,
and perl, rightly, complains. And at this point I'm stumped... again.

	Justin.

-- 
Justin C, by the sea.


------------------------------

Date: Thu, 19 Feb 2009 11:30:31 -0600
From: gbacon@hiwaay.net (Greg Bacon)
Subject: Re: Sorting hash of hashes
Message-Id: <v8udnd57X_OqCgDUnZ2dnUVZ_qDinZ2d@posted.hiwaay2>

It looks like you must have called Dumper(%hashes). What you really
want is Dumper(\%hashes) -- note the backslash -- so you can later
evaluate the dump to create an equivalent hash.

Note that %hashes is a really bad name. I don't make this comment
to pick on you: good names make code easier to think about and write.
When choosing names, don't describe the implementation details such
as hash or array, but use the same terms you would when explaining
your approach to a non-technical person.

You described your structure with

    $hashes{$report}{$line}{$colNumber}

so %report is probably a better name. (I assume stk1324r2 is a
report code.)

You can sort and print the descriptions with

    print map "$_\n",
          sort
          map { my $r = $report{$_};
                map ref $r->{$_} && $r->{$_}{2} ? $r->{$_}{2} : (),
                    keys %$r;
              }
          keys %report;

I don't recommend this approach, but it's instructive. Read it
bottom-to-top:

    1. For each possible report code (keys %report)
    2. Make note of where we are in the hash ($r = $report{$_})
    3. Make sure it's a report code (ref $r->{$_} && $r->{$_}{2})
    4. Extract the description from column 2.

You can make it a little nicer if you can infer from the key that
its value is a report (say, if it starts with "stk"):

    print map "$_\n",
          sort
          map { my $r = $report{$_}; map $r->{$_}{2}, keys %$r; }
          grep /^stk/,
          keys %report;

I take it you want more than the descriptions, though. Do you also
need the "paths" to get to them?

Hope this helps,
Greg
-- 
The idea that the vote of a people, no matter how nearly unanimous, makes or
creates or determines what is right or just becomes as absurd and
unacceptable as the idea that right and justice are simply whatever a king
says they are.             -- Robert Welch


------------------------------

Date: 19 Feb 2009 17:39:05 GMT
From: xhoster@gmail.com
Subject: Re: Sorting hash of hashes
Message-Id: <20090219123800.776$xX@newsreader.com>

justin.news@purestblue.com wrote:
> On 2009-02-19, Justin C <justin.0810@purestblue.com> wrote:
> > Here's how my hash looks:
> >
> > $hashes{$report}{$line}{$colNumber}
> >
> > So, in %hashes, is data from several reports, grouped by report, then
> > line (well, stock code, which is the first field on the line), the
> > column number. Here is a little of the output of Data::Dumper:
> >
> > $VAR1 = 'types';
> > $VAR2 = {
> >           'BE' => 1
> >         };
> > $VAR3 = 'stk1324r2';
> > $VAR4 = {

 ...

You should give Dumper a reference to your hash, not the flattened list
of your hash.  Then there would be only one $VARx and it reflect the true
structure you have.


> I've looked further at this and found a "sort hash by value" example.
> Looking at it, I remember it from the Llama. I can see how to apply that
> to a simple hash, "@sorted = sort { $hash{$a} cmp $hash{$b} } keys
> %hash". But am not sure how to make $hashes{$report}{$item}{2} fit.
>
> What I've got is:
>
> my @sorted = sort byAlpha ( keys ( %{$hashes{$report}} ) );
>
> sub byAlpha {
>     $hashes{$report}{$item}{2}{a} cmp $hashes{$report}{$item}{2}{a};
> }

What is the last {a} for?  You don't have such a critter in your data dump,
the value associated with key 2 is a string, not a hashref with 'a' as a
key.

It seems like it should be
 $hashes{$report}{$a}{2} cmp $hashes{$report}{$b}{2};

> And, of course, $report is not passed to the sub and is therefore undef,
> and perl, rightly, complains. And at this point I'm stumped... again.

Don't use a named subroutine as the sort's code block, just put the code
directly into the sort block.  That way it executes in the context of
the sort, where $report is defined.

Xho

-- 
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.


------------------------------

Date: Thu, 19 Feb 2009 12:37:37 -0600
From: gbacon@hiwaay.net (Greg Bacon)
Subject: Re: Sorting hash of hashes
Message-Id: <QqGdnRnTtt1sOwDUnZ2dnUVZ_sudnZ2d@posted.hiwaay2>

: I take it you want more than the descriptions, though. Do you also
: need the "paths" to get to them?

If that's the approach you're after, use code similar to the following:

    my $DESC_COLUMN = 2;

    sub item_paths {
      my($report) = @_;

      my @descs;

      foreach my $code (keys %$report) {
        next unless $code =~ /^stk/ && ref $report->{$code};

        foreach my $line (keys %{ $report->{$code} }) {
          push @descs => [ $code, $line ]
            if exists $report->{$code}{$line}{$DESC_COLUMN};
        }
      }

      @descs;
    }

    print map "$_\n",
          sort
          map $report{ $_->[0] }{ $_->[1] }{ $DESC_COLUMN },
          item_paths \%report;

Hope this helps,
Greg
-- 
America's central bank needs a chief whose ideas are as loopy as the
economy he is meant to run. Bernanke seems like just the man for the job.
    -- The Daily Reckoning, 2005/11/07


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

#The Perl-Users Digest is a retransmission of the USENET newsgroup
#comp.lang.perl.misc.  For subscription or unsubscription requests, send
#the single line:
#
#	subscribe perl-users
#or:
#	unsubscribe perl-users
#
#to almanac@ruby.oce.orst.edu.  

NOTE: due to the current flood of worm email banging on ruby, the smtp
server on ruby has been shut off until further notice. 

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

#To request back copies (available for a week or so), send your request
#to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
#where x is the volume number and y is the issue number.

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 2221
***************************************


home help back first fref pref prev next nref lref last post