PrePAN

Sign in to PrePAN

Hash::Squash Remove numbered keys from a nested object

Good

Synopsis

=head1 SYNOPSIS

=head2 C<squash>

B<squash> does 3 things to the argument recursively

1. Remove numbered keys from hashes and map them to arrays

2. Convert hashes/arrays with single element to single value

3. Convert empty hashes/arrays to `undef`

    use Hash::Squash qw(squash);
    my $hash = squash(+{
        foo => +{
            '0' => 'numbered',
            '1' => 'hash',
            '2' => 'structures',
        },
        bar => +{
            '0' => 'obviously a single value',
        },
        buz => [
            +{
                nest => +{
                    '0' => 'nested',
                    '2' => 'discreated',
                    '3' => 'array',
                },
            },
            +{
                nest => +{
                    '0' => 'FOO',
                    '1' => 'BAR',
                    '2' => 'BUZ',
                },
            },
        ],
    });

Turns to:

    +{
        foo => [
            'numbered',
            'hash',
            'structures',
        ],
        bar => 'obviously a single value',
        buz => [
            +{
                nest => [
                    'nested',
                    undef,
                    'discreated',
                    'array',
                ],
            },
            +{
                nest => [
                    'FOO',
                    'BAR',
                    'BUZ',
                ],
            }
        ],
    };

=head2 C<unnumber>

B<unnumber> is similar to B<squash>, but keep hashes/arrays

    use Hash::Squash qw(unnumber);
    my $hash = unnumber(+{
        foo => +{
            '0' => 'numbered',
            '1' => 'hash',
            '2' => 'structures',
        },
        bar => +{
            '0' => 'obviously a single value',
        },
        buz => [
            +{
                nest => +{
                    '0' => 'nested',
                    '2' => 'partial',
                    '3' => 'array',
                },
            },
        ],
    });

Turns to:

    +{
        foo => [
            'numbered',
            'hash',
            'structures',
        ],
        bar => ['obviously a single value'],
        buz => [
            +{
                nest => [
                    'nested',
                    undef,
                    'partial',
                    'array',
                ],
            },
        ],
    };

Description

This package provides B and B subroutines to simplify hash/array structures.

Comments

Might I suggest using another name? Object::Squash implies that the module does something to objects, but it seems it works on hashes. The word "Squash" is rather generic and implies compression. The module does something very specific (it converts hash elements with numeric keys into arrays) which isn't really a compression, but a mapping of sorts.
Ah, I agree. how do you feel the name like Hash::Unnumber ?
How about Hash::MapToArray? I'd look on CPAN to see if there's an existing idiom.

On the other hand, having just looked at CPAN, I discovered Hash::Convert. Would that do what you need without requiring a new module?
Thank you djerius@github.

I will change the module to focus narrowly on removing numbers.
Hash::MapToArray gives me the impression that returns an array or array ref.
How about Hash::Arrayish?

I need a recursive solution. (Sorry, this requirement is not clear from its SYNOPSIS, I'll fix it)
To put it bluntly, this module is to deal with stringified arrays from PHP in my case.
The $rules argument from Hash::Convert looks kind of making code tricky a bit.
Ok, how about Data::Rmap?

use Data::Rmap qw[ rmap_hash ];
use Scalar::Util 'looks_like_number';
use Data::Dumper;

my $hash = +{
foo => +{
'0' => 'nested',
'1' => 'numbered',
'2' => 'hash',
'3' => 'structures',
'4' => {
'0' => 'nested value'
},
},
bar => +{
'0' => 'obviously a single value',
},
};

my $id = 0;

my ($nhash) = rmap_hash {

my $local_id = ++$id;

$_[0]->recurse;

return if $local_id == 1;

my @array;
my $h = $_;

$array[$_] = $h->{$_}
for grep { looks_like_number $_ } keys %$h;

$_ = @array == 1 ? $array[0] : \@array;

} $hash;

print Dumper $hash;

Please sign up to post a review.