Correct data structure / sort method to use

  • Thread starter Niall Macpherson
  • Start date
N

Niall Macpherson

I have a problem sorting a hash by value rather than key. I have read
the FAQ concerning this but unfortunately it does not help . I am not
sure if this is due to with my misunderstanding of the way the sort
function works or due to me not using the correct data structure.

I have a number of database spaces each of which has a unique name
which I am using as the hash key . Each key has a size, used and free
attribute associated with it . So a typical entry would look like

$dbspaces{space67}{size} = 12345;
$dbspaces{space67}{used} = 123;
$dbspaces{space67}{free} = 12222;

I wish to sort the hash based on the 'used' value.

I do understand that I cannot sort the hash directly , I have to sort
the keys and then access the hash by the sorted keys - this is fine.

I do understand also that it may be better to use a hash of arrays ,
although I would prefer to be accessing $dbspaces{space67}{size} than
$dbspaces{space67}[0] for readability.

My problem is that I do not seem to be able to access the hash within
the sort function.

i.e if I use the format

my @sort_by_used_keys = sort sort_by_used (keys %dbspaces);

the sort function 'sort_by_used()' only has access to the $a and $b
variables, not the hash itself.

All the examples I have seen which access the hash itself seem to do so
using the 'inline' (hope that is the correct terminology) version of
sort - e.g

@sorted = sort { lc($hash{$a}) cmp lc($hash{$b}) } keys %hash;

Attached is a very cut down version of the code. It will compile and
run although it will not do anything since the 'sort_by_used' function
cannot access the hash and I therefore cannot perform the correct tests
within this function I would be grateful if someone could tell nme
what I am doing wrong.

Many thanks

use strict;
use warnings;
use Data::Dumper;

##--------------------------------------------------------------
sub sort_by_used
{
## How do I access the hash here ?

# This will not compile
#return ($dbspaces{$a}{used} <=> dbspaces{$b}{used})

return(0);
}
##--------------------------------------------------------------
##
## Note - cannot sort a hash directly.
##
## Need to sort the hash keys and then access the hash
## via the sorted array
##--------------------------------------------------------------

my %dbspaces = ();
my $key = "";

## Populate the hash
while(<DATA>)
{
chomp;
my @vals = split;
$key = $vals[0];
$dbspaces{$key}{size} = $vals[1];
$dbspaces{$key}{used} = $vals[2];
$dbspaces{$key}{free} = $vals[3];
}

print Dumper %dbspaces;

## Sort by the used attribute
my @sort_by_used_keys = sort sort_by_used (keys %dbspaces);

## Access the hash by the sorted keys, i.e used descending
foreach $key (@sort_by_used_keys)
{
print Dumper $dbspaces{$key};
}
exit(0);

__END__
space1 100 63 37
space2 200 12 188
space47 300 299 1
space99 400 375 25
 
A

Anno Siegel

Niall Macpherson said:
I have a problem sorting a hash by value rather than key. I have read
the FAQ concerning this but unfortunately it does not help . I am not
sure if this is due to with my misunderstanding of the way the sort
function works or due to me not using the correct data structure.

I have a number of database spaces each of which has a unique name
which I am using as the hash key . Each key has a size, used and free
attribute associated with it . So a typical entry would look like

$dbspaces{space67}{size} = 12345;
$dbspaces{space67}{used} = 123;
$dbspaces{space67}{free} = 12222;

I wish to sort the hash based on the 'used' value.
[...]

My problem is that I do not seem to be able to access the hash within
the sort function.

i.e if I use the format

my @sort_by_used_keys = sort sort_by_used (keys %dbspaces);

the sort function 'sort_by_used()' only has access to the $a and $b
variables, not the hash itself.

Then make the hash(ref) a parameter of the function instead of (or in
addition to) the keys. Untested:

sub sort_by_used {
my $hr = shift;
sort { $hr->{ $a}->{ used} <=> $hr->{ $b}->{ used} } keys %$hr;
}

Anno
 
G

Gunnar Hjalmarsson

Niall said:
My problem is that I do not seem to be able to access the hash within
the sort function.

i.e if I use the format

my @sort_by_used_keys = sort sort_by_used (keys %dbspaces);

the sort function 'sort_by_used()' only has access to the $a and $b
variables, not the hash itself.

No. All you need to do is declaring the %dbspaces variable before
sort_by_used().
 
N

Niall Macpherson

Anno Siegel wrote:

Then make the hash(ref) a parameter of the function instead of (or in
addition to) the keys. Untested:

sub sort_by_used {
my $hr = shift;
sort { $hr->{ $a}->{ used} <=> $hr->{ $b}->{ used} } keys %$hr;
}

Anno
--

Thanks Anno . I would rather go with this than with Gunnars suggestion
since in my real program which is much larger, the %dbspaces hash is
not a global variable and I would prefer to pass it to the sort
function explicitly.

I had kind of figured this might be the besty way to go but I still
don't understand how $a and $b get passed through to the sort
subroutine though and therefore cannot figure out how to pass
aditional parameters.

I tried changing

my @sort_by_used_keys = sort sort_by_used ( keys %dbspaces);

to

my @sort_by_used_keys = sort sort_by_used ( \%dbspaces, keys
%dbspaces);

but then in the sort_by_used sub I don't appear to get the value ..

sub sort_by_used
{
my $hr = shift;

print Dumper $hr;
return(0);
}

gives me

$VAR1 = undef;
 
A

Anno Siegel

Niall Macpherson said:
Anno Siegel wrote:



Thanks Anno . I would rather go with this than with Gunnars suggestion
since in my real program which is much larger, the %dbspaces hash is
not a global variable and I would prefer to pass it to the sort
function explicitly.

I had kind of figured this might be the besty way to go but I still
don't understand how $a and $b get passed through to the sort

The system takes care of $a and $b, they're none of your business.
subroutine though and therefore cannot figure out how to pass
aditional parameters.

What have $a and $b to do with additional parameters?
I tried changing

my @sort_by_used_keys = sort sort_by_used ( keys %dbspaces);
^^^^
What is the second sort() for? It will destroy the order sort_by_used()
has established.
to

my @sort_by_used_keys = sort sort_by_used ( \%dbspaces, keys
%dbspaces);

but then in the sort_by_used sub I don't appear to get the value ..

sub sort_by_used
{
my $hr = shift;

print Dumper $hr;
return(0);
}

gives me

$VAR1 = undef;

Not if you call sort_by_used as shown, it would show the content of
%dbspaces.

If you want to pass the keys as parameters, the sub should in some
way make use of them. Yours doesn't.

sub sort_by_used {
my $hr = shift;
sort { $hr->{ $a}->{ used} <=> $hr->{ $b}->{ used} @_;
}

Anno
 
N

Niall Macpherson

Anno said:
If you want to pass the keys as parameters, the sub should in some
way make use of them. Yours doesn't.

sub sort_by_used {
my $hr = shift;
sort { $hr->{ $a}->{ used} <=> $hr->{ $b}->{ used} @_;
}

Anno
--
If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers.

Thanks Anno - I realise what my mistake was and that is all now
working as expected. Many thank for the help !
 
D

Dr.Ruud

Niall Macpherson:
I have a problem sorting a hash by value rather than key.

You cannot sort a hash. You can access it in an ordered way, like via an
external index.
 
G

Gunnar Hjalmarsson

Dr.Ruud said:
Niall Macpherson:

You cannot sort a hash. You can access it in an ordered way, like via an
external index.

Well, if you think that's worth mentioning, maybe you should suggest
that the FAQ is altered.

perldoc -q "sort a hash"

;-)
 
D

Dr.Ruud

Gunnar Hjalmarsson:
Dr.Ruud:

Well, if you think that's worth mentioning, maybe you should suggest
that the FAQ is altered.

perldoc -q "sort a hash"
;-)

The FAQ is OK with me: "Instead, you have ...".
 
G

Gunnar Hjalmarsson

Dr.Ruud said:
Gunnar Hjalmarsson:

The FAQ is OK with me: "Instead, you have ...".

Now I see you are right. The FAQ entry does not contradict your statement.
 
D

Dr.Ruud

Gunnar Hjalmarsson:
Dr.Ruud:

Now I see you are right. The FAQ entry does not contradict your
statement.

Does a question have to be valid? No, but the answer has to be.
;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top