Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

map a hash with a default value or exclude

by kayahk (Initiate)
on Sep 13, 2011 at 00:13 UTC ( #925594=perlquestion: print w/replies, xml ) Need Help??
kayahk has asked for the wisdom of the Perl Monks concerning the following question:

this has probably been asked multiple times, but i have a config file in the form of:

sometimes value the is missing, is there a way to exclude the key itself or add a default value to the key using map'ing.
this is the simple code i currently have:
sub load_config { my $self = shift; open(my $fh, $self->{config_file}) or croak "open error".$self->{c +onfig}; %{$self->{info}} = map { chomp; split'='; } <$fh>; close($fh); return $self; }

Replies are listed 'Best First'.
Re: map a hash with a default value or exclude
by GrandFather (Sage) on Sep 13, 2011 at 01:17 UTC

    map returns a list so the solution to your missing value conundrum is to return an empty list for suppressed values. I'm not sure I'd solve this particular problem using a map and the following technique, but the technique is worth knowing about in any case:

    use strict; use warnings; my %info = map {chomp; my @parts = split '='; @parts == 2 && length $parts[1] ? @parts : () } <DATA>; print "$_: $info{$_}\n" for sort keys %info; __DATA__ key=value nokey=


    key: value
    True laziness is hard work
Re: map a hash with a default value or exclude
by toolic (Bishop) on Sep 13, 2011 at 00:33 UTC
    If you can live with a map-less solution, this excludes keys without values:
    use warnings; use strict; use Data::Dumper; $Data::Dumper::Sortkeys = 1; my %info; while (<DATA>) { chomp; my ($k, $v) = split /=/; $info{$k} = $v if length $v; } print Dumper(\%info); __DATA__ a=5 b=6 c= d=7
    $VAR1 = { 'a' => '5', 'b' => '6', 'd' => '7'
    This keeps the key, with a default value:
    while (<DATA>) { chomp; my ($k, $v) = split /=/; $info{$k} = (length $v) ? $v : 666; }
Re: map a hash with a default value or exclude
by kcott (Chancellor) on Sep 13, 2011 at 02:59 UTC

    In the spirit of TIMTOWTDI, here's a method that involves capturing your split() output in an arrayref:

    ... map { chomp; [split'=']; } <$fh>;

    which is subsequently filtered through a second map():

    %{$self->{info}} = map { EXPR } map { chomp; [split'=']; } <$fh>;

    To exclude a key, EXPR is:

    defined $_->[1] ? @$_ : ()

    To use a default value (here I've used the string: undef), EXPR is:

    $_->[1] //= q{undef}; @$_

    -- Ken

      or instead of using the ?: in the "decoding" map for the elimination case you could instead use a grep:

      %{$self->{info}} = map {@$_} grep {defined $_->[1]} map {chomp; [split +'='];} <$fh>;

      In any case generating the array ref doesn't actually seem to be a win in terms of succinctness or comprehensibility.

      True laziness is hard work

        Yet another way, using the 3-argument form of split, which guarantees that the input string is split into two parts and no more or less. The second part would be a string of length 0, instead of an undefined value.

        %{$self->{info}} = map {@$_} grep {$_->[1]} map {chomp; [split '=', $_ +, 2];} <$fh>;

        I prefer this form of split in handling key=value type strings, since it handles the cases where a value could have an embedded '=' (PASSWORD=blah=argh!), whereas the shorter one-(or, two-)argument forms would return truncated values.

        Yet another alternative, using only one map:

        %{$self->{info}} = map {chomp; my ($k, $v) = split '=', $_, 2; $v ? ($ +k => $v) : (); } <$fh>;

        If we want to supply default values:

        # assuming default values are in %defaults %{$self->{info}} = map {chomp; my ($k, $v) = split '=', $_, 2; $k => $ +v || $defaults{$k}; } <$fh>;
Re: map a hash with a default value or exclude
by jethro (Monsignor) on Sep 13, 2011 at 01:18 UTC

    Nothing prevents you from inserting code as complex as you need into the map:

    ... = map { chomp; my ($right,$left)= split'='; if ($left) { ($right,$ +left) } else { () } } <$fh>;
Re: map a hash with a default value or exclude
by jwkrahn (Monsignor) on Sep 13, 2011 at 05:02 UTC
    is there a way to exclude the key itself

    %{$self->{info}} = map /^([^=]+)=(.+)$/, <$fh>;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://925594]
Approved by toolic
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (3)
As of 2017-08-19 18:06 GMT
Find Nodes?
    Voting Booth?
    Who is your favorite scientist and why?

    Results (312 votes). Check out past polls.