4

I have a hash of arrays.

%HoA = (
    'C1' =>  ['1', '3', '3', '3'],
    'C2' => ['3','2'],
    'C3' => ['1','3','3','4','5','5'],
    'C4'  => ['3','3','4'],
    'C5' => ['1'],
);

I would like to write a subroutine that returns a "sub copy" hash of arrays that contains the first N keys (and their values) of the original hash of arrays.

Something like this

my %HoA2 = new_partition(\%HoA, 3);

And it returns a new HoA data structure:

%HoA = (
    'C1' =>  ['1', '3', '3', '3'],
    'C2' => ['3','2'],
    'C3' => ['1','3','3','4','5','5'],
 );

Is there a way to do this by scratch without using a module?

4

2 回答 2

3

There are no "first N elements", as the order of hash keys is not defined and thus, cannot be relied upon.

If you want any three elements instead of first three, you could use

%HoA = @HoA{ ( keys %HoA )[0..2] };
于 2013-03-30T20:46:20.653 回答
3

As has been correctly stated, the order of elements in a hash is undefined. But if you can impose your own order on the elements, then it is simple enough to extract the elements that you require:

my %HoA = (
    'C1' => ['1', '3', '3', '3'],
    'C2' => ['3','2'],
    'C3' => ['1','3','3','4','5','5'],
    'C4' => ['3','3','4'],
    'C5' => ['1'],
);

# Use an array slice to grab the first 3 keys from a sorted list of %HoA keys.
# Use map to create a new hash that contains the keys and the values from the
# original hash:
my %HoA2 = map { $_ => $HoA{$_} } (sort keys %HoA)[0..2];

# Alternatively, specify the exact keys that you require:
my %HoA3 = map { $_ => $HoA{$_} } qw(C1 C2 C3);

# { C1 => [1, 3, 3, 3], C2 => [3, 2], C3 => [1, 3, 3, 4, 5, 5] }

Update

As Borodin points out, the above method copies references, so changes to one hash will be reflected in the other:

push @{$HoA{C1}}, 9;

# %HoA2 and %HoA3:
# { C1 => [1, 3, 3, 3, 9], C2 => [3, 2], C3 => [1, 3, 3, 4, 5, 5] }

To prevent that, copy the array itself:

my %HoA4 = map { $_ => [@{ $HoA{$_} }] } qw(C1 C2 C3);
于 2013-03-30T21:13:43.963 回答