Pathologically Eclectic Rubbish Lister PerlMonks

### Cutting the top percentage out of a Hash

by Gavin (Archbishop)
 on Apr 13, 2006 at 18:28 UTC Need Help??

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

Hi Bretheren,
I was hoping the following would enable me to print out from the input percentage from the hash by key / value pairs. The hash is sorted in a specific order, but it is not coming out in that order. I need to be able to hold the UPDATE insertion order to output.
Any ideas will be much appreciated.
Gavin
```my \$Percent = <STDIN>;
my \$per = \$Percent/100;#percent as decimal
my \$pairs = (keys %lineFinal);# pairs of key/value
my \$counter = 0;# zero counter
my \$amount_to_print = int(\$per * \$pairs);

foreach my \$key ( keys %lineFinal) {
if (\$counter < \$amount_to_print) {
print \$key, ' ', \$lineFinal{\$key}, "\n";
#print OUTPERC \$key, ' ', \$lineFinal{\$key}, "\n";
print OUTPERC "\$key\t \$lineFinal{\$key}\n";
}
else {
last;
}
\$counter++;
}

Replies are listed 'Best First'.
Re: Cutting the top percentage out of a Hash
by ikegami (Patriarch) on Apr 13, 2006 at 18:38 UTC
The hash is sorted in a specific order,

That's impossible. Hashes can't be sorted, as you've noticed. Are you sure an AoA isn't more appropriate here? If you wish to continue using a hash, the typical solution it the sort the data as you read it from the hash, as follows:

```foreach my \$key ( sort { ... } keys %lineFinal) {
...
}

Alternatively, you could use Tie::IxHash instead of a hash. You use it just like a normal hash (thanks to tie), but the contents are ordered.

ikegami,
Alternatively, you could use Tie::IxHash instead of a hash. The syntax is the same (thanks to tie), but the contents are ordered.

It should be made clear that the order is the insertion order and not an arbitrary sort criteria. While the module does provide rudimentary sort capability, it is limited to asciibetical sorts of the keys or values.

Tie::Hash::Sorted may be a better fit.

Cheers - L~R

Thanks for the info
I was hoping to avoid using Tie:: Hash
a) Because I haven't used it before and I'm not sure of syntax.
b) I was hoping for a more simple solution that would avoid installing the Tie:: Hash module
Gavin
Re: Cutting the top percentage out of a Hash
by Codon (Friar) on Apr 13, 2006 at 18:35 UTC
Hashes aren't stored sorted in Perl. You can sort the data bofore you put it in the hash, but the data is stored in an arbitrary order. If you need the contents of the hash sorted, you need to the sort the data as you pull it from the hash.

Ivan Heffner
WhitePages.com, Inc.
Re: Cutting the top percentage out of a Hash
by johngg (Canon) on Apr 13, 2006 at 21:37 UTC
It is probably a good idea to take the plunge and try new modules as other Monks have suggested. However, I have put a script together to show you one way of preserving your insertion order when using hashes. I have used hash references, sometimes called anonymous hashes, which are useful when building complex data structures. Doing \$refToHash = {} creates a reference to an empty hash. They are also useful for passing data into and out of subroutines.

I have taken a random subset of the X11 rgb.txt file as data source in order to build a hash of colours. They are in no particular order but the order they are in can be preserved. I have also used Data::Dumper so you can see what the data structure looks like after we have constructed it.

```use strict;
use warnings;

# Use this to show the data structure.
#
use Data::Dumper;

# Initialise a hash reference and a sequence no.
#
my \$rhPreserve = {};
my \$insertionOrder = 0;

# Read our data line by line, chomping off the newline
# and splitting on the ":" and using the colour name
# as the key and RGB for the value.
#
while(<DATA>)
{
chomp;
my (\$value, \$key) = split /:/;

# Make an entry in the hash reference for this colour but
# the value is another hash with two key/value pairs, one
# for our RGB value and the other the insertion order
# which we increment after insertion.
#
\$rhPreserve->{\$key} =
{
value => \$value,
insertionOrder => \$insertionOrder ++
};
}

# Use Data::Dumper to print out the hash reference so we can see
# what we have constructed. The colour "keys" will come out in an
# order determined by the underlying hashing algorith.
#
my \$dd = Data::Dumper->new([\$rhPreserve], ["rhPreserve"]);
print "Data structure\n", \$dd->Dumpxs();

# To use our insertion order, which we have preserved in the hash
# reference, we can sort by "insertionOrder" then use the sorted keys
# to access the hash reference.
#
my @keysInInsertionOrder =
sort
{
\$rhPreserve->{\$a}->{insertionOrder}
<=>
\$rhPreserve->{\$b}->{insertionOrder}
}
keys %\$rhPreserve;
print "Data in insertion order\n";
foreach (@keysInInsertionOrder)
{
print
"Insertion order - \$rhPreserve->{\$_}->{insertionOrder}\n",
"     Key - \$_\n",
"     Value - \$rhPreserve->{\$_}->{value}\n";
}

__END__
255 250 250:snow
248 248 255:GhostWhite
245 245 245:WhiteSmoke
220 220 220:gainsboro
255 250 240:FloralWhite
253 245 230:OldLace
250 240 230:linen
250 235 215:AntiqueWhite
255 239 213:PapayaWhip
255 235 205:BlanchedAlmond
255 228 196:bisque
255 218 185:PeachPuff
255 222 173:NavajoWhite
255 228 181:moccasin
255 248 220:cornsilk
255 255 240:ivory
255 250 205:LemonChiffon
255 245 238:seashell
240 255 240:honeydew

When run this produces the following

I hope this will help.

Cheers,

JohnGG

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://543175]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2022-06-30 00:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?