Return top-N of Hashes - hash splice?

Discussion in 'Perl Misc' started by Edward Wijaya, Oct 2, 2004.

  1. 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


    --
    Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
    Edward Wijaya, Oct 2, 2004
    #1
    1. Advertising

  2. Edward Wijaya <> wrote:

    > 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?


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Oct 2, 2004
    #2
    1. Advertising

  3. Edward Wijaya wrote:
    > 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
    Jürgen Exner, Oct 2, 2004
    #3
  4. On Sat, 02 Oct 2004 04:14:53 GMT, Jürgen Exner <>
    wrote:

    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
    Edward Wijaya, Oct 2, 2004
    #4
  5. 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
    Edward Wijaya, Oct 2, 2004
    #5
  6. Edward Wijaya wrote:
    > On Sat, 02 Oct 2004 04:14:53 GMT, Jürgen Exner <>
    > wrote:
    >> 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.


    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.

    >> 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.


    Sorry, never used that one.

    jue
    Jürgen Exner, Oct 2, 2004
    #6
  7. Jürgen Exner wrote:
    > Edward Wijaya wrote:
    >>
    >>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.


    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
    --
    use Perl;
    program
    fulfillment
    John W. Krahn, Oct 2, 2004
    #7
  8. Edward Wijaya

    Joe Smith Guest

    Edward Wijaya wrote:

    > On Sat, 02 Oct 2004 04:14:53 GMT, Jürgen Exner <>
    > wrote:
    >> 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.


    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";

    >> 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.


    In that case, use a hash and an array, as shown above.
    -Joe
    Joe Smith, Oct 2, 2004
    #8
  9. Edward Wijaya

    Shawn Corey Guest

    John W. Krahn wrote:
    > 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
    Shawn Corey, Oct 2, 2004
    #9
  10. John W. Krahn wrote:
    > Jürgen Exner wrote:
    >> Edward Wijaya wrote:
    >>>
    >>> 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.

    >
    > 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
    Jürgen Exner, Oct 2, 2004
    #10
  11. Shawn Corey <> wrote:
    > John W. Krahn wrote:
    >> 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,

    ^^^^^^^^^^^

    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?


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Oct 2, 2004
    #11
  12. Edward Wijaya wrote:

    > 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?"
    Chris Mattern, Oct 3, 2004
    #12
  13. In article <1Xp7d.539$x65.53@trnddc06>,
    Jürgen Exner <> wrote:
    >Edward Wijaya wrote:
    >> 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;


    --
    Charles DeRykus
    Charles DeRykus, Oct 7, 2004
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. rp
    Replies:
    1
    Views:
    499
    red floyd
    Nov 10, 2011
  2. Scott  Gilpin
    Replies:
    2
    Views:
    211
  3. Perl Learner

    Hashes of hashes or just one hash ?

    Perl Learner, Jun 8, 2005, in forum: Perl Misc
    Replies:
    11
    Views:
    207
  4. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    201
  5. Replies:
    3
    Views:
    199
Loading...

Share This Page