Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: Hash slice from a hashref, into a hashref

by haukex (Chancellor)
on Apr 25, 2018 at 17:42 UTC ( #1213547=note: print w/replies, xml ) Need Help??


in reply to This is a useless node

I just realized the question is useless.

I'm not sure why you think so, how to take a slice of a hash is a valid question, maybe you could explain what resolution you found for your question?

Anyway, there are several ways to make a (shallow) copy of a part of a hash, here are a few:

  1. Using map: %slice = map { $_ => $hash{$_} } @keys;
  2. Using Foreach Loops (in this case as a statement modifier): $slice{$_} = $hash{$_} for @keys;
  3. Using Slices: @slice{@keys} = @hash{@keys};
  4. Using Key/Value Hash Slices, new in Perl 5.20: %slice = %hash{@keys};
my %h is really big and I don't have enough RAM to make a copy of it

This makes the question interesting. It turns out that, at least on my machine with Perl 5.26, from the options above:

  1. map takes the most memory, about 180% as much as a regular @ slice,
  2. a regular @ slice takes about as much memory as a key/value % slice,
  3. a key/value % slice takes about as much memory as a regular @ slice, and
  4. the for loop variant takes the least amount of memory, taking only about 88% of a regular @ slice.
use warnings; use strict; use feature qw/say/; my %bighash; { my $sz = 1_000_000; my $v = 'aaaaaaaaaaaaaa'; $bighash{$v++} = int(rand($sz))+1 for 1..$sz; } my @keys = keys %bighash; delete $bighash{aaaaaaaaaaaaab}; my %slice; say `ps -orss $$`=~s/\s+/ /gr; #%slice = map { $_ => $bighash{$_} } @keys; #@slice{@keys} = @bighash{@keys}; #%slice = %bighash{@keys}; $slice{$_} = $bighash{$_} for @keys; die if defined $slice{aaaaaaaaaaaaab}; # verify the slice die unless $slice{aaaaaaaaaaaaaa}>0 && $slice{aaaaaaaaaaaaaa}==$bighash{aaaaaaaaaaaaaa}; say `ps -orss $$`=~s/\s+/ /gr;
I want to load the slice directly into a hashref

As it turns out, changing my %slice into my $slice and changing the syntaxes into the following doesn't really make a big difference:

  1. $slice = { map { $_ => $hash{$_} } @keys }; - about 6% more memory
  2. @{$slice}{@keys} = @hash{@keys}; - about the same amount of memory
  3. $slice = {%hash{@keys}}; - about the same amount of memory
  4. $slice->{$_} = $hash{$_} for @keys; - about the same amount of memory

On the other hand, if for example the values in your hash are huge, then perhaps a different approach is needed - for example, in your second hash you could store references to the values of the first hash. Or, you may not even need to create a second hash in the first place, perhaps simply keeping the list of keys around to select values from the first hash is enough.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1213547]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2020-01-22 13:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?