nidhi has asked for the wisdom of the Perl Monks concerning the following question:

My result from a perl script is :
a => 15-19,30,35,120 b => 15-17,30,35,40, c => 15-18,30,35,120 And I want : a => 15,16,17,18,19,30,35,120 b => 15,16,17,30,35,40, c => 15,16,17,18,30,35,120
Can Someone suggest how I accomplish this ?
I am trying to store individual value for each key, traverse through each value for presence of "-", and replace it with the required digits.

Replies are listed 'Best First'.
Re: hash with multiple values per key
by shmem (Chancellor) on Aug 10, 2007 at 20:14 UTC
    First thing that comes to mind...
    %hash = ( a => '15-19,30,35,120', b => '15-17,30-35,40', c => '15-18,30,35,120', ); for (keys %hash ) { ($s = $hash{ $_}) =~ s/-/../g; $hash{$_} = join(',',eval $s); }; print "$_ => $hash{$_}\n" for sort keys %hash; __END__ a => 15,16,17,18,19,30,35,120 b => 15,16,17,30,31,32,33,34,35,40 c => 15,16,17,18,30,35,120

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: hash with multiple values per key
by FunkyMonk (Bishop) on Aug 10, 2007 at 20:17 UTC
    How about

    while ( <DATA> ) { chomp; my ( $lhs, $rhs ) = split /\s+=>\s+/; my $ans = "$lhs => " . join ",", map { /(\d+)-(\d+)/ ? $1 .. $2 : $_ } split /,/; print "$ans\n" } __DATA__ a => 15-19,30,35,120 b => 15-17,30,35,40, c => 15-18,30,35,120 __END__ a => 15,16,17,18,19,30,35,120 b => 15,16,17,30,35,40 c => 15,16,17,18,30,35,120

Re: hash with multiple values per key
by bobf (Monsignor) on Aug 10, 2007 at 20:09 UTC

    Since you didn't provide any code, I'll assume that you know how to iterate over the keys of the hash, etc.

    If the list of numbers and ranges in each value is in numerical order, you could use Set::IntSpan. If you need more help, please be more specific. Also, don't forget about Super Search. number sequence offers many solutions that solve this problem - please refer to that node for more information.

Re: hash with multiple values per key
by wind (Priest) on Aug 10, 2007 at 20:42 UTC

    It's not entirely clear what format your initial data structure is taking. Are the values a single string? Are an array of values?

    Assuming that they are array refs, and that your ranges are ordered from lesser value to greater value, this should work just fine:

    my %hash = ( a => ['15-19',30,35,120], b => ['15-17','30-35',40], c => ['15-18',30,35,120], ); for (values %hash) { @$_ = map {/^(\d+)-(\d+)$/ ? ($1..$2) : $_} @$_; } use Data::Dumper; print Dumper(\%hash);
    If your ranges could be reversed, then the following adaptation would work:
    for (values %hash) { @$_ = map {!/^(\d+)-(\d+)$/ ? $_ : ($1 < $2) ? ($1..$2) : reverse +($2..$1)} @$_; }
    - Miller

      This would allow negatives:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $test = { a => '-15-19,30,35,120', b => '15-17,30,35,40', c => '15-18,30,35,120' }; for my $key (keys %$test) { print "Processing '$key'\n"; $test->{$key} = [ map { /(-?\d+)-(-?\d+)/ ? ($1..$2) : 0+$_ } split(',', $test->{$key}) ]; } print Dumper($test);

      And one more with regex:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $test = { a => '-15-19,30,35,120', b => '15-17,30,35,40', c => '15-18,30,35,120' }; for my $key (keys %$test) { print "Processing '$key'\n"; $test->{$key} =~ s/(-?\d+)-(-?\d+)/join(",", ($1..$2))/eg; $test->{$key} = [split(',', $test->{$key} )]; } print Dumper($test);

      ___________
      Eric Hodges
Re: hash with multiple values per key
by nidhi (Acolyte) on Aug 10, 2007 at 20:13 UTC
    thanx bobf for directing me to the right thread. I believe, it will be helpful
Re: hash with multiple values per key
by nidhi (Acolyte) on Aug 10, 2007 at 20:33 UTC
    Awesome guys..am overwhelmed by the replies..they r bang on target!!!
Re: hash with multiple values per key
by Anonymous Monk on Aug 11, 2007 at 03:42 UTC

    On the other hand, it is certainly not a smart idea to store this way. The original format makes much more sense.