Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > perl style: can I combine two steps into one?

Reply
Thread Tools

perl style: can I combine two steps into one?

 
 
Michael Slass
Guest
Posts: n/a
 
      02-04-2005
I have a hash where the keys are strings and the values are integers.
I wanted to produce a report of the name/value pairs, sorted by the
integers in descending order.

I came up with this:

,----
| #!/usr/bin/perl -w
| use strict;
|
| my %hack_count;
| my @report;
|
| # read in ssh attempts from /var/log/messages*
| while (<>)
| {
| if (/sshd.+rhost=(\S+)/)
| {
| ++$hack_count{$1};
| }
| }
|
| # create a list of (count, ip) cells, sorted by count
| my ($ip, $count);
| while (($ip, $count) = each %hack_count)
| {
| push @report, [$count, $ip];
| }
|
| foreach (sort { $b->[0] <=> $a->[0]; } @report) {
| printf("%-50s\t%4d\n", $_->[1], $_->[0]);
| }
`----

Is there a way to combine the "each" and "push" statements so I don't
need the intermediate variables $ip and $count? The order of the
variables in the anonymous lists is not important; I just put the
numerical value first since I figured I'd remember to sort on the
first element of the anonymous lists.

Thanks.

--
Mike Slass
 
Reply With Quote
 
 
 
 
Paul Lalli
Guest
Posts: n/a
 
      02-04-2005
"Michael Slass" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> I have a hash where the keys are strings and the values are integers.
> I wanted to produce a report of the name/value pairs, sorted by the
> integers in descending order.
>
> I came up with this:

<snip>
> | # create a list of (count, ip) cells, sorted by count
> | my ($ip, $count);
> | while (($ip, $count) = each %hack_count)
> | {
> | push @report, [$count, $ip];
> | }

<snip>

> Is there a way to combine the "each" and "push" statements so I don't
> need the intermediate variables $ip and $count?


my @report = map {[$hack_count{$_}, $_]} keys %hack_count;
# OR . . .
my @report;
push @report, [$hack_count{$_}, $_] for keys %hack_count;

Of course, these are both still using an intermediate variable of $_.
That may or may not be 'good enough' for you.

Paul Lalli

 
Reply With Quote
 
 
 
 
John Bokma
Guest
Posts: n/a
 
      02-04-2005
Michael Slass wrote:

> I have a hash where the keys are strings and the values are integers.
> I wanted to produce a report of the name/value pairs, sorted by the
> integers in descending order.
>
> I came up with this:
>
> ,----
>| #!/usr/bin/perl -w


drop the -w and

use warnings;

>| # read in ssh attempts from /var/log/messages*
>| while (<>)
>| {
>| if (/sshd.+rhost=(\S+)/)
>| {
>| ++$hack_count{$1};


I recommend using $hack_count{$1}++;

[ sorting ]

printf "%-50s\t%4d\n", $_, $hack_count{ $_ }
for sort { $hack_count{ $b }<=>$hack_count{ $a } } keys %hack_count;


--
John Small Perl scripts: http://johnbokma.com/perl/
Perl programmer available: http://castleamber.com/
Happy Customers: http://castleamber.com/testimonials.html

 
Reply With Quote
 
mjl69
Guest
Posts: n/a
 
      02-04-2005

> I have a hash where the keys are strings and the values are integers.
> I wanted to produce a report of the name/value pairs, sorted by the
> integers in descending order.
>
> I came up with this:
>
> ,----
> | #!/usr/bin/perl -w
> | use strict;
> |
> | my %hack_count;
> | my @report;
> |
> | # read in ssh attempts from /var/log/messages*
> | while (<>)
> | {
> | if (/sshd.+rhost=(\S+)/)
> | {
> | ++$hack_count{$1};
> | }
> | }
> |
> | # create a list of (count, ip) cells, sorted by count
> | my ($ip, $count);
> | while (($ip, $count) = each %hack_count)
> | {
> | push @report, [$count, $ip];
> | }
> |
> | foreach (sort { $b->[0] <=> $a->[0]; } @report) {
> | printf("%-50s\t%4d\n", $_->[1], $_->[0]);
> | }
> `----
>
> Is there a way to combine the "each" and "push" statements so I don't
> need the intermediate variables $ip and $count? The order of the
> variables in the anonymous lists is not important; I just put the
> numerical value first since I figured I'd remember to sort on the
> first element of the anonymous lists.
>
> Thanks.
>
> --
> Mike Slass
>
>


@report = map {[$_->[1], $_->[0]]}sort {$b->[0] <=> $a->[0]} map {[$hack_count{$_}, $_]} keys %hack_count;

 
Reply With Quote
 
Michael Slass
Guest
Posts: n/a
 
      02-04-2005
"Paul Lalli" <(E-Mail Removed)> writes:

>"Michael Slass" <(E-Mail Removed)> wrote in message
>news:(E-Mail Removed)...
>> I have a hash where the keys are strings and the values are integers.
>> I wanted to produce a report of the name/value pairs, sorted by the
>> integers in descending order.
>>
>> I came up with this:

><snip>
>> | # create a list of (count, ip) cells, sorted by count
>> | my ($ip, $count);
>> | while (($ip, $count) = each %hack_count)
>> | {
>> | push @report, [$count, $ip];
>> | }

><snip>
>
>> Is there a way to combine the "each" and "push" statements so I don't
>> need the intermediate variables $ip and $count?

>
>my @report = map {[$hack_count{$_}, $_]} keys %hack_count;
># OR . . .
>my @report;
>push @report, [$hack_count{$_}, $_] for keys %hack_count;
>
>Of course, these are both still using an intermediate variable of $_.
>That may or may not be 'good enough' for you.
>
>Paul Lalli
>


Ahh.. didn't know about map. That's perfect, thank you. I'll read
the docs about it.

--
Mike Slass
 
Reply With Quote
 
John Bokma
Guest
Posts: n/a
 
      02-04-2005
mjl69 wrote:

[ snip ]

my @report =

map { [ $_->[ 1 ], $_->[ 0 ] ] }
sort { $b->[ 0 ] <=> $a->[ 0 ] }
map { [ $hack_count{ $_ }, $_ ] }
keys %hack_count;

Amazing how things can become more readable by careful reformating

--
John Small Perl scripts: http://johnbokma.com/perl/
Perl programmer available: http://castleamber.com/
Happy Customers: http://castleamber.com/testimonials.html

 
Reply With Quote
 
mjl69
Guest
Posts: n/a
 
      02-05-2005

> mjl69 wrote:
>
> [ snip ]
>
> my @report =
>
> map { [ $_->[ 1 ], $_->[ 0 ] ] }
> sort { $b->[ 0 ] <=> $a->[ 0 ] }
> map { [ $hack_count{ $_ }, $_ ] }
> keys %hack_count;
>
> Amazing how things can become more readable by careful reformating


I was just looking for a place to use the Schwartzian Transform. It is kind of a stretch. He did not really need the elements of the anonymous array reversed at the end (the beginning).

mjl

>
> --
> John Small Perl scripts: http://johnbokma.com/perl/
> Perl programmer available: http://castleamber.com/
> Happy Customers: http://castleamber.com/testimonials.html
>
>

 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      02-05-2005
John Bokma <(E-Mail Removed)> wrote in comp.lang.perl.misc:
> Michael Slass wrote:



> >| ++$hack_count{$1};

>
> I recommend using $hack_count{$1}++;


Why?

Anno
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      02-05-2005
mjl69 <(E-Mail Removed)> wrote in comp.lang.perl.misc:
>
> > mjl69 wrote:
> >
> > [ snip ]
> >
> > my @report =
> >
> > map { [ $_->[ 1 ], $_->[ 0 ] ] }
> > sort { $b->[ 0 ] <=> $a->[ 0 ] }
> > map { [ $hack_count{ $_ }, $_ ] }
> > keys %hack_count;
> >
> > Amazing how things can become more readable by careful reformating

>
> I was just looking for a place to use the Schwartzian Transform. It is
> kind of a stretch. He did not really need the elements of the anonymous
> array reversed at the end (the beginning).


It is not a good example to demonstrate the Schwartzian Transform. Its
point is to avoid the repeated calculation of a sort key by replacing
it with access to a Perl data structure (a list of pairs). When sorting
by the values of a hash, we already have a data structure that gives
fast access to the sort keys -- the hash itself. There is little
point in building another for sorting. That the OP *wants* a very
similar data structure is a different consideration.

On the other hand, the Schwartzian transform doesn't hinge on he fact
that the sort key is the first element of each pair. Building the
wanted structure from the start and indexing on 1 wouldn't make it
less of one. The final (top) step is unnecessary and missing now,
so it's only half of a Schwartzian still.

sort { $b->[ 1] <=> $a->[ 1] }
map [ $_, $hack_count{ $_}],
keys %hack_count;

Anno
 
Reply With Quote
 
John Bokma
Guest
Posts: n/a
 
      02-05-2005
Anno Siegel wrote:

> John Bokma <(E-Mail Removed)> wrote in comp.lang.perl.misc:
>> Michael Slass wrote:

>
>
>> >| ++$hack_count{$1};

>>
>> I recommend using $hack_count{$1}++;

>
> Why?


Post increment is more used, and hence more natural to read. I only use pre
increment when it does matter. If I see ++$var I wonder what is happening
there. Like another example I posted last week somewhere else:

(pseudocode)

i = 0
while (true) {


i++;
last if i >= 10;
}

I consider >= 10 misleading if the previous statement is the only one that
modifies i. It can't get > 10 , so why test for it?

--
John Small Perl scripts: http://johnbokma.com/perl/
Perl programmer available: http://castleamber.com/
Happy Customers: http://castleamber.com/testimonials.html

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
How to combine two JPGs into one Don Wiss Digital Photography 20 03-19-2008 05:13 PM
Combine many files into one using perl kishore.maheshwari@gmail.com Perl Misc 5 03-22-2006 09:15 PM
Combine two dictionaries into a list of 3-tuples Nickolay Kolev Python 3 11-10-2004 09:25 PM
Does Perl combine multiple REs into a single automaton? Clint Olsen Perl Misc 2 06-29-2004 04:57 PM
How can I combine two modem bandwidth? Jane Lee A+ Certification 3 09-27-2003 04:50 AM



Advertisments