Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have my hash with the following structure - not sure it is the good one, considering I want $topic, and $index be also keys -
$bighash{$key1}{$key2}{$key3}{$key4}[$topic-1][$index-1] = $total;
The hash: keys 50:20:6:4, topic 1, and 5 index with its totals and so on
$VAR1 = {'50' -> { ..........'20' -> { .............'6' -> { ...............'4' -> | ...................| ....................'30', ....................'40', ....................'20', ....................'20', ....................'10' ....................|, ....................| ....................'28', ....................'10', ....................'76', ....................'20', ....................'10' ....................|, ........{'60' => { ..........'30' => { ............'6' => { ...............'4' => | | ....................'30',
For each set of keys in specific $topic I have a set of index: index1, index2, index3...indexN and its total I want to sort the $index by the value of its $total, without affecting the order of the $keys and $topic and return...
$VAR1 = {'50' => { ...........'20' => { ............'6' => { .............'4' => | .....................| ....................'40',=>index2 ....................'30',=>index1 ....................'20',=>index3 ....................'20',=>index4 ....................'10'=>index5 .....................|,
I wrote the word "index.." besides each total as an example, because I need to keep track of which index was, as another key. So maybe my initial hash structure was not ok.

How do I sort those values without affecting the whole hash structure?, and is it my hash structure? OK?

Thanks

edited by ybiC: balanced <code> tags around output examples

Replies are listed 'Best First'.
Re: sorting an array of hashes by the value of the keys
by dragonchild (Archbishop) on Aug 12, 2003 at 14:09 UTC
    I'm going to go out on a limb and guess that you're reading a bunch of bioinformatics data. I'm also going to guess that this data is (or can be easily) sorted at your source. I'm also guessing that you want to just get this information.

    Given all of that, you probably should only read the info from the file that you need, then do your calculations. After that, discard the data you've gotten and go to the next group. (This will reduce your memory needs by at least 90%, given a typical bioinformatics dataset.)

    Now, if you do that, you don't need to split your initial key into four keys. In fact, since all the data you're working with has to do with those, you don't need to use it as a key at all. So, all you have is your topic, your index, and your value - a standard 2-D data structure. Try working with that and see how far you get.

    If your data isn't sorted, I would sort it first and save that to some file (or set of files). Then, use that as your data source for summations and the like.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: sorting an array of hashes by the value of the keys
by sgifford (Prior) on Aug 12, 2003 at 18:40 UTC

    Here's what I would do.

    First, get a list of all of the hash keys you want to sort. Since the hash is so deeply nested, it may be easiest to store the results in an array ref:

    foreach my $k1 (keys %bighash) { foreach my $k2 (keys %{$bighash{$k1}}) { ... push(@keys,[$k1, $k2, ...]);
    Now that you have the keys in an array, you can sort them:
    @keys = sort by_key_total @keys; sub by_key_total { $bighash{$a->[1]}{$a->[2]}{$a->[3]}{$a->[4]}[$a->[5]][$a->[6]] <=> $bighash{$b->[1]}{$b->[2]}{$b->[3]}{$b->[4]}[$b->[5]][$b->[6]] }
Re: sorting an array of hashes by the value of the keys
by sweetblood (Prior) on Aug 12, 2003 at 14:13 UTC
    You cannot change the "sort order" of a hash. Hashes appear to have a randoness to their order. So what you want is to sort the result of your hash, not the hash it self.

      Not true. Of course you can sort a hash. The random part is the order in which the keys get inserted, but if you do

      sort(keys %hash)
      you'll get the keys in alphabetical order. If you do
      sort { $a <=> $b } keys %hash;
      you'll get the keys in numerical order.

      The only thing you can't get from the hash is the order in which things were added

      Update: I can't type ... switched can get to can't get in the sentence above, sort of changes the meaning :)

      Update: sauoq is correct and I'm completely wrong (not the first time) I wasn't thinking about the fact that sort is simply returning the keys in the order which you ask. The original remains the same. Apologies sweetblood.

      Lobster Aliens Are attacking the world!
        Of course you can sort a hash.

        Well, no. You really can't. You can, as your examples show, generate a list of the sorted keys of a hash¹. You can do the same with the values. But the hash itself remains unsorted.

        Contrast that with an array, a structure that you can sort:

        perl -le '@a = qw(b c a); @a = sort @a; print "@a"'
        The equivalent for a hash, something like %h = map { $_, $h{$_} } sort keys %h; does a lot of work for no good reason. (And, %h = sort %h wouldn't even keep the key/value pairs intact.) There is simply no way to sort a hash.

        1. People are usually perfectly happy with this solution. My guess is that the monk to which you were responding was either being pedantic or was reciting something by rote that he recently learned.

        -sauoq
        "My two cents aren't worth a dime.";