Kage has asked for the wisdom of the Perl Monks concerning the following question:
Okay..I have a Users Online script that also shows how many users are on each page... I want it to order the showing via how many users... so if it is like this:
12 users page_url..
6 users page_url..
14 users page_url..
1 user page_url..
then it will put it in decending order, the highest amount first, then down. and if there is like, for example, 3 pages that have the same amount of users, like
2 users page_url...
2 users page_url2...
2 users page_url3...
then it will just rank it in any way...I don't care how that part is ranked. This is the code used:
everything is held in foreach $loc (@locations){ } and the number of users online is in ${$loc}{online} (then ${$loc}{users} which says "user" or "users" depending on the number, and $loc which is the actual location, so it all is mainly like this:
foreach $loc (@locations){
print "${$loc}{online} ${$loc}{users} $loc\n";
}
so, how do I have it display it in foreach depending on the # of users?
Re: Stupid, yet simple, sort question
by davorg (Chancellor) on Oct 24, 2001 at 20:46 UTC
|
Argh! You're using symbolic references aren't you.
Please don't do that. It's nasty.
Here's how you do it using your system. Hopefully
someone else will have more time and will be able to
show you how you should do it using real
references.
foreach my $loc (sort {${$b}{online} <=> ${$a}{online}}
@locations) {
print "${$loc}{online} ${$loc}{users} $loc\n";
}
--
<http://www.dave.org.uk>
"The first rule of Perl club is you don't talk about
Perl club."
| [reply] [Watch: Dir/Any] [d/l] |
Re: Stupid, yet simple, sort question
by ChemBoy (Priest) on Oct 24, 2001 at 20:42 UTC
|
foreach my $loc (sort {$b->{users} <=> $a->{users}} @locations){
...
}
should do the trick.
Update: updated to what joealba was suggesting as I updated it (though without the intermediate step implied by what I said in chatter right before ;-).
Update 2: or, using the correct field...
foreach my $loc (sort {$b->{online} <=> $a->{online}} @locations){
...
}
<sheepish grin>
If God had meant us to fly, he would *never* have given us the railroads.
--Michael Flanders | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Just sort it right the first time.. don't reverse it after.
foreach my $loc (sort {$b->{users} <=> $a->{users}} @locations) {
...
}
UPDATE: I wanna be like ChemBoy when I grow up. :)
UPDATE2:Kage, please do yourself a favor. Restructure your data structures into one nice neat hash.
%pages = (
'page1' => 2,
'page2' => 24,
'page3' => 8,
);
foreach my $loc (sort {$pages{$b} <=> $pages{$a}} keys %pages) {
my $s = "s" unless $pages{$loc} == 1;
print "$pages{$loc} user$s accessing $loc\n";
...
}
Update 129: See the entire recoded solution below | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Stupid, yet simple, sort question
by jeroenes (Priest) on Oct 24, 2001 at 21:32 UTC
|
A few style remarks:
- try 'use strict' for a change.
- try to avoid reeling in outside info in your
namespace... use nested structures instead. perlref, perldsc, perllol to name a few.
A link to perlreftut can be found in my homenode.
- read up on sort and perlop. Use these kind of constructs to sort nested structures
@sorted_keys = sort { $HoH{$b}{'number'} <=> $HoH{$a}->{'number'} } ke
+ys %HoH;
- The require 'config.txt' looks questionable, to say the least. Try to use a real config format, like AppConfig.
- Try to minimalize the use of reserved words (see perlfunc ).
They are very confusing..
So, your code:
open(FILE,$log);
flock (FILE,3);
@users=<FILE>;
close(FILE);
foreach $lines (@users){
chop($lines);
($ips,$times,$locationold)=split('×',$lines );
$timeoff=$time-$times;
push @locations,$locationold if (!$exists{$locationold});
$exists{$locationold}=1;
${$locationold}{online}++;
foreach $loc (@locations){
if(${$loc}{online} < "2") {
${$loc}{users} = "user";
} else {
${$loc}{users} = "users";
}
}
foreach $loc (@locations){
print "${$loc}{online} ${$loc}{users} $loc\n";
}
Could be written as:
use strict;
use warnings;
use CGI::Carp qw/fatalsToBrowser/;
open(FILE,$log) or die "Couldn't open $log: $!";
flock (FILE,3) or die "Couldn't lock $log: $!";
my @users=<FILE>;
close(FILE);
chomp @users;
my %locations;
foreach my $lines (@users){
my ($ips,$times,$location)=split('×',$lines);
$timeoff=$time-$times;
if ( not exists $locations{$location}) {
$locations{$location}={online => 1};
} else {
$locations{$location}->{'online'}++;
}
}
$location{$_}->{'usertext'}=$location{$_}->{'online'}==1? 'user' : 'us
+ers' for keys %locations;
foreach my $loc (sort { $b->{'online'} <=> $a->{'online'} }keys %locat
+ions){
my $href = $locations{$loc};
print $href->{'online'}." ".$href->{'usertext'}."$loc\n";
}
To start with. I have added: Hashes of hashes, strict compliance (sort of), die statement as open check,
fatalstobrowser, and more things.... it's only a start. Code still unchecked, may contain typos etc.
Hope this gets you on your way.... Jeroen
"We are not alone"(FZ)
Updated... still more to come, I guess. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Stupid, yet simple, sort question
by broquaint (Abbot) on Oct 24, 2001 at 20:38 UTC
|
This ought do the trick -
foreach $loc (reverse sort { int(${$a}{online}) <=> int(${$b}{online})
+ } @locations)
HTH
broquaint
Update: And if I look the at code a little closer, it may even work (dereferenced the info we want, thanks davorg) | [reply] [Watch: Dir/Any] [d/l] |
Re: Stupid, yet simple, sort question
by Kage (Scribe) on Oct 24, 2001 at 20:44 UTC
|
Okay...I got 3 answers...all three sound right...but I don't know which to use..I need the most efficient one..
#1:
sort{ $a->{users} ,<=> $b->{users} } @locations
#2
for my $loc ( sort { $a->{users} <=> $b->{users} } @locations )
#3
foreach $loc (reverse sort { int($a) <=> int($b) } @locations)
Which one is the most efficient one? I need one that can take at least 3,000 different ranks...thats the stress limit of my script and it must be able to handle the stress limit.. | [reply] [Watch: Dir/Any] [d/l] |
|
None of them will work, as they all assume that you're
using hard references - which you aren't.
Unless I've completely misunderstood your code.
--
<http://www.dave.org.uk>
"The first rule of Perl club is you don't talk about
Perl club."
| [reply] [Watch: Dir/Any] |
|
As noted in chatter, davorg was correct about Kage
using symbolic referencees but was incorrect in thinking
that the syntax $a->{key} does not work when
$a isn't a "hard" reference (that is, when $a simply contains
the name of some global hash variable).
Of course, use strict would prevent it from
working, but that also prevents ${$a}{key}
from working.
-
tye
(but my friends call me "Tye")
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Re: Stupid, yet simple, sort question
by Kage (Scribe) on Oct 24, 2001 at 21:01 UTC
|
this is most all of what it does:
require "config.txt";
$refresh="60";
$ip=$ENV{'REMOTE_ADDR'};
$time=time;
open(FILE,$log);
flock (FILE,3);
@users=<FILE>;
close(FILE);
foreach $lines (@users){
chop($lines);
($ips,$times,$locationold)=split('×',$lines);
$timeoff=$time-$times;
push @locations,$locationold if (!$exists{$locationold});
$exists{$locationold}=1;
${$locationold}{online}++;
foreach $loc (@locations){
if(${$loc}{online} < "2") {
${$loc}{users} = "user";
} else {
${$loc}{users} = "users";
}
}
foreach $loc (@locations){
print "${$loc}{online} ${$loc}{users} $loc\n";
}
| [reply] [Watch: Dir/Any] [d/l] |
|
require "config.txt";
my $refresh="60";
my $ip=$ENV{'REMOTE_ADDR'};
my $time=time;
open(FILE,$log) or die "Couldn't open $log: $!\n";
flock (FILE,3);
my @users=<FILE>;
close(FILE);
my %pages;
foreach my $line (@users){
chomp($line);
my ($ips,$times,$location)=split('×',$line);
$pages{$location}++;
}
foreach my $loc (sort {$pages{$b} <=> $pages{$a}} keys %pages) {
my $s = "s" unless $pages{$loc} == 1;
print "$pages{$loc} user$s accessing $loc\n";
}
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
|