christian
christian

Reputation: 55

Remove empty strings in Perl hash of arrays

I have a hash with this structure

{
  a => ['1', '2', '', '5', '6', '7', '8'],
  b => ['1', '2', '3', '6', '7', '8', '9'],
  c => ['2', '', '4', '', '', '8', ''],
}

And I need some like this

{
  c => ['2', '4', '8'], 
  a => ['1', '2', '5', '6', '7', '8'], 
  b => ['1', '2', '3', '6', '7', '8', '9']
}

How can I delete the '' values?

Upvotes: 2

Views: 1173

Answers (4)

mpapec
mpapec

Reputation: 50677

You can directly change list of array references returned by values as described in perldoc.

use warnings;
my %h = (
  'c' => ['2','','4','','','8',''],
  'a' => ['1','2','','5','6','7','8'],
  'b' => ['1','2','3','6','7','8','9']
);

@$_ = grep defined && length, @$_ for values %h;

and in the case that undef values should not be filtered out,

@$_ = grep !defined || length, @$_ for values %h;

Upvotes: 11

Borodin
Borodin

Reputation: 126762

None of the answers you have seen so far consider the possibility that the hash values may be anything other than simple strings or numbers.

While that may be appropriate to your data, it isn't a safe assumption in general.

This example modifies the hash in place, removing only empty string values and preserving everything else.

Note that, even though it may need to be installed, Data::Dump is usually a better choice than Data::Dumper, as shown here.

use strict;
use warnings;

my @alpha = ('a' .. 'm');

my $hash = {
  a => ['1', '2', '', '5', '6', '7', '8'],
  b => ['1', '2', '3', '6', '7', '8', '9'],
  c => ['2', '', '4', '', '', '8', ''],
  d => ['5', '', '6', '', undef, '22', '', 'aa', -51.2, \@alpha],
};

for my $list (values %$hash) {
  for (my $i = $#{$list}; $i >= 0; --$i) {
    my $item = $list->[$i];
    splice(@{$list}, $i, 1) if defined $item and $item eq '';
  }
}

use Data::Dump;
dd $hash;

output

{
  a => [1, 2, 5 .. 8],
  b => [1, 2, 3, 6 .. 9],
  c => [2, 4, 8],
  d => [5, 6, undef, 22, "aa", -51.2, ["a" .. "m"]],
}

Upvotes: 2

user1558455
user1558455

Reputation:

since the op wanted to get a hash back, here is a quick solution which works fine :)

use strict;
use warnings; 
use Data::Dumper;
use feature 'say';

my %h = (
  'c' => ['2','','4','','','8',''],
  'a' => ['1','2','','5','6','7','8'],
  'b' => ['1','2','3','6','7','8','9']
);

foreach my $keys ( keys %h) {
    $h{$keys} = [grep { length $_ } @{$h{$keys}}];
}

say Dumper \%h;

Upvotes: 0

hmatt1
hmatt1

Reputation: 5159

mpapec has already posted a nice succinct answer, but I figured I post my solution too.

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my %hash = (    c => ['2','','4','','','8',''],
                a => ['1','2','','5','6','7','8'],
                b => ['1','2','3','6','7','8','9'],
        );

for my $key (keys %hash) {
        my @temp_array = ();
        for my $element ( @{$hash{$key}} ) {
                if ( $element ne "" ) { # only remove empty strings
                        push @temp_array, $element;
                }

        }
        $hash{$key}=\@temp_array;
}

print Dumper %hash;

This traverses the whole data structure and maybe that will help if you need to access the elements for other things. Here's the output:


$VAR1 = 'c';
$VAR2 = [
          '2',
          '4',
          '8'
        ];
$VAR3 = 'a';
$VAR4 = [
          '1',
          '2',
          '5',
          '6',
          '7',
          '8'
        ];
$VAR5 = 'b';
$VAR6 = [
          '1',
          '2',
          '3',
          '6',
          '7',
          '8',
          '9'
        ];

Upvotes: 2

Related Questions