Return top-N of Hashes - hash splice?

E

Edward Wijaya

Hi

With this hashes:

$hash = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

What's the best to retrieve the top-N hashes
from it. So, with N = 3 it will become:

$hash_top3 = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
};

Thanks beforehand.

Regards,
Edward WIJAYA
SINGAPORE
 
T

Tad McClellan

Edward Wijaya said:
With this hashes:

$hash = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

What's the best to retrieve the top-N hashes


Hashes do not have a "top". They are UNordered.

If you need to preserve the order, then you have chosen
the wrong data structure.


What is it that you are actually trying to accomplish?
 
J

Jürgen Exner

Edward said:
With this hashes:

$hash = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

What's the best to retrieve the top-N hashes
from it. So, with N = 3 it will become:

Hashes by definition don't have a (usable) sequence or order. Therefore your
request for the top n elements of a hash doesn't make any sense.

If you want/need to preserve the sequence of elements then you picked the
wrong data structure.
Use an array instead. And to get the first $n elements use an array slice
@foo = @bar[0..$n-1];

jue
 
E

Edward Wijaya

Hi,
Thanks so much for the reply:
Hashes by definition don't have a (usable) sequence or order. Therefore
your request for the top n elements of a hash doesn't make any sense.

Sorry for not being clear before.
I should have sorted the hash according to it's value
and then pick top-N from it.
Use an array instead.
It's difficult for me to change the current
data-structure of my code, as it's inherently designed
for hash.

Moreover, I found about Tie::IxHash module.
Which is suppose to "impose" order in the hash.
However since I am new in using Method through external
module, there are 2 issues I fail to deal with.
Your valuable suggestion is important to me.

Here is my code:

__BEGIN__
use strict;
use warnings;
use Tie::IxHash;

my $N = 2;
my %hash = {
#1) Must sort by value,then 2) Select Top N after sorting it.
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

my $t = Tie::IxHash->new(%hash);
$t->SortByValue; #sorting it, is this correct?
my @topN = $t->Splice(0, $N); #splicing it

__END__

My problem is:
1. Is the way I invoke the Sorted new hash is correct?,
How can I view it? I tried: print "%$hash\n"; # doesn't seem to work
2. The "spliced" array is in the form of array,
Is there any efficient way/method to recover it into Hash?

Thanks and hope to hear from you again,

Regards
Edward WIJAYA
SINGAPORE
 
E

Edward Wijaya

Sorry.
Slight correction, the hash should come with bracket:

my %hash =(
#1) Must sort by value,then 2) Select Top N after sorting it.
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
);


Regards,
Edward WIJAYA
SINGAPORE
 
J

Jürgen Exner

Edward said:
Sorry for not being clear before.
I should have sorted the hash according to it's value
and then pick top-N from it.

Again, a hash does not have a (usable) sequence, therefore the very notion
of sorting a hash doesn't make sense.

You may sort a list of the keys of the hash (sort keys %myhash) or a list of
the values of the hash (sort values %myhash), but you cannot sort a hash.
It's difficult for me to change the current
data-structure of my code, as it's inherently designed
for hash.

Moreover, I found about Tie::IxHash module.

Sorry, never used that one.

jue
 
J

John W. Krahn

Jürgen Exner said:
Again, a hash does not have a (usable) sequence, therefore the very notion
of sorting a hash doesn't make sense.

You may sort a list of the keys of the hash (sort keys %myhash) or a list of
the values of the hash (sort values %myhash), but you cannot sort a hash.

Sure you can. A hash returns a list like any other list.

$ perl -le' %x = qw/ a b c d x y /; print for %x; print; print for sort %x'
c
d
a
b
x
y

a
b
c
d
x
y



John
 
J

Joe Smith

Edward said:
Sorry for not being clear before.
I should have sorted the hash according to it's value
and then pick top-N from it.

You cannot sort a hash. Period.

You can sort the hash keys into a list and then use that list to
access the corresponding values in order by key, but the hash
itself remains unsorted.

@sorted_keys = sort keys %hash;
print "$_ -> $hash{$_}\n" for @sorted_keys;
print "keys: @sorted_keys\n";
print "values: @hash{@sorted_keys}\n";

Or you can create an array of keys sorted such that the corresponding
values are in order.

$N = $number_of_items_to_extract;
@keys_sorted_by_value = sort { $hash{$a} cmp $hash{$b} } keys %hash;
@top_N_keys = splice @keys_sorted_by_value,-$N;
print "The keys @top_N_keys have values @hash{@top_N_keys}\n";
print "The remaining values are @hash{@keys_sorted_by_value}\n";
It's difficult for me to change the current
data-structure of my code, as it's inherently designed
for hash.

In that case, use a hash and an array, as shown above.
-Joe
 
S

Shawn Corey

John said:
Sure you can. A hash returns a list like any other list.

$ perl -le' %x = qw/ a b c d x y /; print for %x; print; print for sort %x'

No, these convert the hash to an array, then sorts it.

--- Shawn
 
J

Jürgen Exner

John said:
Sure you can. A hash returns a list like any other list.

$ perl -le' %x = qw/ a b c d x y /; print for %x; print; print for
sort %x' c

Ok, I never thought of it that way!
Good that I set my coffee down before reading your post, otherwise I would
have to clean my keyboard now....

This is really a good one, should keep it in mind for the next person asking
how to sort a hash.

jue
 
T

Tad McClellan

Shawn Corey said:
No, these convert the hash to an array,
^^^^^^^^^^^

No it doesn't.

There is no array being used anywhere in that code.

See this Perl FAQ:

What is the difference between a list and an array?
 
C

Chris Mattern

Edward said:
Hi

With this hashes:

$hash = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

What's the best to retrieve the top-N hashes
from it. So, with N = 3 it will become:

"Non sequitur. Your facts are uncoordinated."
There is no such thing as "the top-N hashes".
Hashes are unordered. Any attempt to think about
getting the "first" or "top" N elements of hash
will only bring you pain and grief. What are
you actually trying to do?
$hash_top3 = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
};

Thanks beforehand.

Regards,
Edward WIJAYA
SINGAPORE

--
Christopher Mattern

"Which one you figure tracked us?"
"The ugly one, sir."
"...Could you be more specific?"
 
C

Charles DeRykus

Edward said:
With this hashes:

$hash = {
'1-1' => 3,
'2-3' => 2,
'2-2' => 1,
'1-2' => 6,
'1-3' => 3
};

What's the best to retrieve the top-N hashes
from it. So, with N = 3 it will become:

Hashes by definition don't have a (usable) sequence or order. Therefore your
request for the top n elements of a hash doesn't make any sense.

If you want/need to preserve the sequence of elements then you picked the
wrong data structure.
Use an array instead. And to get the first $n elements use an array slice
@foo = @bar[0..$n-1];

Or, possibly, use Tie::IxHash to preserve order:

my $tie = Tie::IxHash->new( '1-1'=>3, '2-3'=>2, '2-2'=>1,
'1-2'=>6, '1-3'=>3 );

print $tie->Keys($_),"=>",$tie->Values($_),"\n" for 0..2;
 

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

Similar Threads


Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top