Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Problem with sorting a hash 2

Status
Not open for further replies.

majorbiff

Programmer
Mar 8, 2005
53
0
0
AU
I have a hash array that needs to be sorted.
Problem is, I can't get the elements to sort themselves correctly as I can't just sort by the keys.

My hash data looks like this:

key value
12345678 123, 12:00 25/7/2005: myemail@dumpster.org
12345680 124, 12:01 25/7/2005: another@dumpster.org

Key: 8 char value that can include A-F and 0-9
Value: index number, time, date, email address

I want to sort by the index number.

I have this so far:
Code:
foreach (sort {(split(/,/,$a))[0] <=> (split(/,/,$b))[0]} values %emailList){
		$flatList .= "$_: $emailList{$_} <br>";
	}

$flatList is passed out of the function and printed to screen.

It works, but the key value is omitted.
I know that I am not passing the $_ value correctly and thats where I need some hints.

Thanks.

Alchemy is easy with Perl!:
s/lead/gold/g
 
Belay the previous. Ive got it solved:
Code:
foreach (sort {(split(/,/,$emailList{$a}))[0] <=> (split(/,/,$emailList{$b}))[0]} keys %emailList){
		$flatList .= "$_: $emailList{$_} <br>";
	}

Alchemy is easy with Perl!
s/lead/gold/g;
 
another way:

Code:
my %emailList = (
12345683 => '125, 12:01 25/7/2005: another@dumpster.org',
12345678 => '123, 12:00 25/7/2005: myemail@dumpster.org',
12345680 => '124, 12:01 25/7/2005: another@dumpster.org',
12345644 => '127, 12:01 25/7/2005: another@dumpster.org',
12345684 => '126, 12:01 25/7/2005: another@dumpster.org'
);

my %hash = reverse %emailList;
print "$array{$_}: $_\n" for (sort {$a <=> $b} keys %hash);

prints:

Code:
12345678: 123, 12:00 25/7/2005: myemail@dumpster.org
12345680: 124, 12:01 25/7/2005: another@dumpster.org
12345683: 125, 12:01 25/7/2005: another@dumpster.org
12345684: 126, 12:01 25/7/2005: another@dumpster.org
12345644: 127, 12:01 25/7/2005: another@dumpster.org

if the "index" numbers are always numeric it sould work as is.
 
sorry, I noticed an error in my code, this line:

Code:
print "[b]$array[/b]{$_}: $_\n" for (sort {$a <=> $b} keys %hash);

should be:

Code:
print "[b]$hash[/b]{$_}: $_\n" for (sort {$a <=> $b} keys %hash);
 
maybe the simplest way would be like this:

Code:
print "$_: $emailList{$_}\n" for (sort {$emailList{$a} <=> $emailList{$b}} keys %emailList);

don't even have to reverse the hash or split the values.
 
This would be ideal for a Schwartzian Transform:
Code:
my $flatList;
for (
      map $_->[ 0 ],
      sort { $a->[ 1 ] <=> $b->[ 1 ] }
      map [ $_, ( split /[,:]? /, $emailList{ $_ } )[0] ], keys %emailList ) {

        $flatList .= "$_: $emailList{$_} <br>";
}
This reduces the number of times the split has to happen (once per line, as opposed to twice per comparison) and so increases efficiency.
 
simpler to flatten the hash first
Code:
print sort map {"$_: $emailList{$_}<br>"} keys %emailList;
achieves the same.

f

&quot;As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.&quot;
--Maurice Wilkes
 
fishiface - that'll sort on the hash key - the OP wants to sort on the first field in the value (the three-digit number).
 
dead right. I wondered why you were going all Schwartzian on me. Blame the liquid lunch.

f ;-)

&quot;As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.&quot;
--Maurice Wilkes
 
ishnid,

but there is no need to split the value anyway is there? Once the sort function (using the <=> operator) hits the first comma does it not stop trying to sort on any further data in the string? So effectively it is just sorting on the digits before the first comma, no?
 
I wasn't aware of that. It *does* appear to behave like that alright, though I can't find that behaviour documented anywhere - have you a link to the official behaviour?

With warnings enabled, it throws an ``argument isn't numeric'' warning, which is why I've never noticed this behavior (since I always use warnings, apart from in one-liners).
 
No there is no official behaviour that I am aware of in this regards. You will get the not-numeric warning if you have warnings enabled. I noticed this behaviour quite a long time ago and found it to be useful.
 
That's interesting - and it does make this paricular solution easier. The only thing is that I'd personally be a little uncomfortable relying on undocumented behaviour.
 
I don't think it stops on the comma, just when it has enough info to determine the result of the comparison. The results would be the same even if it didn't stop.

f

&quot;As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.&quot;
--Maurice Wilkes
 
Nice work ishnid, have a star. Thanks to KevinADC too. Many good ideas.
The script doesn't have to be fast, but a Schwartzian Transform is a nice touch.

Alchemy is easy with Perl!
s/lead/gold/g;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top