How can I use MAP to increment values in an array?

Discussion in 'Perl Misc' started by Mr P, May 10, 2010.

  1. Mr P

    Mr P Guest

    I have an array in which I want to add a counter - for example, change
    CAT to CAT #:

    ....so
    CAT
    DOG
    CAT
    MOUSE
    EEL
    CAT

    becomes
    CAT 1
    DOG
    CAT 2
    MOUSE
    EEL
    CAT 3

    Obviously I can write a little loop like

    my $c = 0;
    for ( @a )
    {
    next unless /^CAT/;
    $c++; # wow that's weird
    $_ .= " $c";
    }

    But what I'd prefer is something like

    my $c = 1;
    map s/^(CAT)/$1 $c++/e, @a;

    I read and read on this, and I also tried:
    map s/^(CAT)/$1 $c++/e, @a;

    since it appeared that within the RHS of the s///, a single + was an
    increment operator.

    Am I in the ballpark here guys? Everything I've tried results in
    interpreter errors.

    Thanks,
    MP
     
    Mr P, May 10, 2010
    #1
    1. Advertising

  2. Mr P

    Mr P Guest

    On May 10, 3:44 pm, Mr P <> wrote:
    > I have an array in which I want to add a counter - for example, change
    > CAT to CAT #:
    >
    > ...so
    > CAT
    > DOG
    > CAT
    > MOUSE
    > EEL
    > CAT
    >
    > becomes
    > CAT 1
    > DOG
    > CAT 2
    > MOUSE
    > EEL
    > CAT 3
    >
    > Obviously I can write a little loop like
    >
    > my $c = 0;
    > for ( @a )
    > {
    >   next unless /^CAT/;
    >   $c++; # wow that's weird
    >   $_ .= " $c";
    >  }
    >
    > But what I'd prefer is something like
    >
    >   my $c = 1;
    >   map s/^(CAT)/$1 $c++/e, @a;
    >
    > I read and read on this, and I also tried:
    >   map s/^(CAT)/$1 $c++/e, @a;
    >
    > since it appeared that within the RHS of the s///, a single + was an
    > increment operator.
    >
    > Am I in the ballpark here guys? Everything I've tried results in
    > interpreter errors.
    >
    > Thanks,
    > MP


    oops I mean I ALSO TRIED s/^(CAT)/$1 $c+/e, @a; # single +
     
    Mr P, May 10, 2010
    #2
    1. Advertising

  3. Mr P

    Uri Guttman Guest

    >>>>> "P" == P <> writes:

    P> my $c = 0;
    P> for ( @a )
    P> {
    P> next unless /^CAT/;
    P> $c++; # wow that's weird

    wierd in what way?

    P> $_ .= " $c";
    P> }

    P> But what I'd prefer is something like

    P> my $c = 1;
    P> map s/^(CAT)/$1 $c++/e, @a;

    that won't work. the replacement is an expression with /e. you are
    thinking it is a string AND an expression. so make an expression
    (multiple statements are allowed) with the last one being the
    replacement value. something like this: (untested)

    s/^(CAT)/$c++ ; "$1 $c:/e foreach @a;

    and don't use map without returning a list. foreach modifier is better
    for that.

    P> I read and read on this, and I also tried:
    P> map s/^(CAT)/$1 $c++/e, @a;

    P> since it appeared that within the RHS of the s///, a single + was an
    P> increment operator.

    huh??

    P> Am I in the ballpark here guys? Everything I've tried results in
    P> interpreter errors.

    well, everything you tried is a syntax error. as i said, the code in the
    replacement part must be a valid expression under /e.

    this by itself is not valid perl:

    $1 $c++

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, May 10, 2010
    #3
  4. Mr P

    Dr.Ruud Guest

    Mr P wrote:
    > I have an array in which I want to add a counter - for example, change
    > CAT to CAT #:
    >
    > ....so
    > CAT
    > DOG
    > CAT
    > MOUSE
    > EEL
    > CAT
    >
    > becomes
    > CAT 1
    > DOG
    > CAT 2
    > MOUSE
    > EEL
    > CAT 3


    perl -MData::Dumper -wle'
    my (@r, %c);
    push @r, [$_, ++$c{$_}]
    for qw/ CAT DOG CAT MOUSE EEL CAT /;
    print Dumper(\@r);
    '

    --
    Ruud
     
    Dr.Ruud, May 10, 2010
    #4
  5. Mr P

    Dr.Ruud Guest

    Dr.Ruud wrote:
    > Mr P wrote:


    >> I have an array in which I want to add a counter - for example, change
    >> CAT to CAT #:
    >>
    >> ....so
    >> CAT
    >> DOG
    >> CAT
    >> MOUSE
    >> EEL
    >> CAT
    >>
    >> becomes
    >> CAT 1
    >> DOG
    >> CAT 2
    >> MOUSE
    >> EEL
    >> CAT 3

    >
    > perl -MData::Dumper -wle'
    > my (@r, %c);
    > push @r, [$_, ++$c{$_}]
    > for qw/ CAT DOG CAT MOUSE EEL CAT /;
    > print Dumper(\@r);
    > '


    And use %c to decide whether you want to print the "1".

    perl -MData::Dumper -wle'
    my (@r, %c, $k);
    push @r, [$_, ++$c{$_}] for qw/ CAT DOG CAT MOUSE EEL CAT /;
    print $k=$_->[0], $c{$k}>1 ? " $_->[1]" : "" for @r;
    '
    CAT 1
    DOG
    CAT 2
    MOUSE
    EEL
    CAT 3

    --
    Ruud
     
    Dr.Ruud, May 10, 2010
    #5
  6. Mr P

    Mr P Guest

    ]
    >   P>   $c++; # wow that's weird
    >
    > wierd in what way?

    Weird in that the variable name accidentally stumbled on another
    language? Just a little bad humor Uri no worries..

    >
    >   P>   $_ .= " $c";
    >   P>  }
    >
    >   P> But what I'd prefer is something like
    >
    >   P>   my $c = 1;
    >   P>   map s/^(CAT)/$1 $c++/e, @a;
    >
    > that won't work. the replacement is an expression with /e. you are
    > thinking it is a string AND an expression. so make an expression
    > (multiple statements are allowed) with the last one being the
    > replacement value. something like this: (untested)
    >
    > s/^(CAT)/$c++ ; "$1 $c:/e foreach @a;
    >
    > and don't use map without returning a list. foreach modifier is better
    > for that.

    respectfully- this is just another way to specify a for loop-
    precisely what I was trying to avoid..


    >
    >   P> I read and read on this, and I also tried:
    >   P>   map s/^(CAT)/$1 $c++/e, @a;
    >
    >   P> since it appeared that within the RHS of the s///, a single + was an
    >   P> increment operator.
    >
    > huh??

    Maybe I mis-read
    >
    >   P> Am I in the ballpark here guys? Everything I've tried results in
    >   P> interpreter errors.
    >
    > well, everything you tried is a syntax error. as i said, the code in the
    > replacement part must be a valid expression under /e.
    >
    > this by itself is not valid perl:
    >
    > $1 $c++
    >
    > uri

    -
    > ---------  Gourmet Hot Cocoa Mix  ----  http://bestfriendscocoa.com---------


    Thanks Uri and everyone, but to summarize , what I'm attempting to do,
    apparently, isn't supported..

    It seems odd to me that it's not, I want to MAP an incremented value
    over an array- sounds like a perfectly logical thing to want to do?

    I realize of course from my, and everyone else's contributions, there
    are myriad ways to accomplish this with for or foreach. But that's
    precisely what I DID NOT want to do. THat's the beauty and elegance of
    map- it operates in 2D.
     
    Mr P, May 11, 2010
    #6
  7. Mr P

    Mr P Guest


    >
    > perl -MData::Dumper -wle'
    >    my (@r, %c);
    >    push @r, [$_, ++$c{$_}]
    >      for qw/ CAT DOG CAT MOUSE EEL CAT /;
    >    print Dumper(\@r);
    > '
    >
    > --
    > Ruud


    Thank-You sir but I was looking for a "mapish" one-liner. I like your
    style though!
     
    Mr P, May 11, 2010
    #7
  8. On 2010-05-11 19:18, Mr P <> wrote:
    >>
    >>   P>   $_ .= " $c";
    >>   P>  }
    >>
    >>   P> But what I'd prefer is something like
    >>
    >>   P>   my $c = 1;
    >>   P>   map s/^(CAT)/$1 $c++/e, @a;
    >>
    >> that won't work. the replacement is an expression with /e. you are
    >> thinking it is a string AND an expression. so make an expression
    >> (multiple statements are allowed) with the last one being the
    >> replacement value. something like this: (untested)
    >>
    >> s/^(CAT)/$c++ ; "$1 $c:/e foreach @a;
    >>
    >> and don't use map without returning a list. foreach modifier is better
    >> for that.

    > respectfully- this is just another way to specify a for loop-
    > precisely what I was trying to avoid..


    In some sense map is also just another way to specify a for loop.

    The difference is mainly that map returns a result, but for doesn't. So
    the rule in perl is: If you are interested in the result, use map.
    Otherwise use for.

    You don't use the result of the map, so you should use for.
    (it does the same thing, but it's more readable)


    >>   P> I read and read on this, and I also tried:
    >>   P>   map s/^(CAT)/$1 $c++/e, @a;

    [...]
    >> well, everything you tried is a syntax error. as i said, the code in the
    >> replacement part must be a valid expression under /e.
    >>
    >> this by itself is not valid perl:
    >>
    >> $1 $c++
    >>

    >
    > Thanks Uri and everyone, but to summarize , what I'm attempting to do,
    > apparently, isn't supported..


    It is. Uri already gave you one solution. Plus several hints in the
    right direction.

    I'll give you another hint:

    Uri wrote that
    $1 $c++
    by itself is not valid perl.

    You cannot (for example) write
    $x = $1 $c++;

    How would you write this line, so that it becomes valid Perl and does
    what you want? If you know this you also know how to rewrite your
    substitution so that it works.

    hp
     
    Peter J. Holzer, May 11, 2010
    #8
  9. Mr P

    Uri Guttman Guest

    >>>>> "P" == P <> writes:

    >>   P>   my $c = 1;
    >>   P>   map s/^(CAT)/$1 $c++/e, @a;
    >>
    >> that won't work. the replacement is an expression with /e. you are
    >> thinking it is a string AND an expression. so make an expression
    >> (multiple statements are allowed) with the last one being the
    >> replacement value. something like this: (untested)
    >>
    >> s/^(CAT)/$c++ ; "$1 $c:/e foreach @a;
    >>
    >> and don't use map without returning a list. foreach modifier is better
    >> for that.


    P> respectfully- this is just another way to specify a for loop-
    P> precisely what I was trying to avoid..

    huh?? map IS a loop too! you are just using map for the loop and not for
    the primary purpose which is to return a list. since you don't return a
    list, don't mislead the code reader with map. use foreach modifier which
    says i am doing something in a loop and not building up a list.
    >>
    >>   P> I read and read on this, and I also tried:
    >>   P>   map s/^(CAT)/$1 $c++/e, @a;
    >>
    >>   P> since it appeared that within the RHS of the s///, a single + was an
    >>   P> increment operator.
    >>
    >> huh??

    P> Maybe I mis-read
    >>
    >>   P> Am I in the ballpark here guys? Everything I've tried results in
    >>   P> interpreter errors.
    >>
    >> well, everything you tried is a syntax error. as i said, the code in the
    >> replacement part must be a valid expression under /e.
    >>
    >> this by itself is not valid perl:
    >>
    >> $1 $c++
    >>
    >> uri

    P> -
    >> ---------  Gourmet Hot Cocoa Mix  ----  http://bestfriendscocoa.com---------


    P> Thanks Uri and everyone, but to summarize , what I'm attempting to do,
    P> apparently, isn't supported..

    no, your brain isn't supporting it. perl can do what you want as long as
    you code it correctly. you have SYNTAX errors in your code. as well as a
    misunderstanding of the semantics of /e.

    P> It seems odd to me that it's not, I want to MAP an incremented value
    P> over an array- sounds like a perfectly logical thing to want to do?

    stop capitalizing MAP. it is map and you really want foreach modifier as
    i keep saying. otherwise you are misleading the code reader. this is not
    an obsfucation contest, use the correct feature.

    P> I realize of course from my, and everyone else's contributions,
    P> there are myriad ways to accomplish this with for or foreach. But
    P> that's precisely what I DID NOT want to do. THat's the beauty and
    P> elegance of map- it operates in 2D.

    no it doesn't. you don't get map vs foreach modifier vs a full
    loop. they ALL LOOP. they are different in syntax and semantics but they
    are all loops. you need a loop. even a /g on your s/// will be a
    LOOP. you can't avoid LOOPS if you want to do something over and over.

    and you can even avoid map likely with a /g modifier. but i don't think
    i will help you until you learn about perl LOOPS, implied or explicit.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, May 11, 2010
    #9
  10. Mr P

    Willem Guest

    Mr P wrote:
    )> s/^(CAT)/$c++ ; "$1 $c:/e foreach @a;
    )>
    )> and don't use map without returning a list. foreach modifier is better
    )> for that.
    ) respectfully- this is just another way to specify a for loop-
    ) precisely what I was trying to avoid..

    map is also just another way to specify a for loop.

    ) Thanks Uri and everyone, but to summarize , what I'm attempting to do,
    ) apparently, isn't supported..

    Of course it is. If you want to keep the original array intact,
    and you want a *new* array with the counters added, *then* map is
    useful:

    my $c = 0;
    my @result = map { $_.(/^CAT$/ && ' '.++$c) } @source;

    But that's still a loop over each separate element of the array.

    ) It seems odd to me that it's not, I want to MAP an incremented value
    ) over an array- sounds like a perfectly logical thing to want to do?
    )
    ) I realize of course from my, and everyone else's contributions, there
    ) are myriad ways to accomplish this with for or foreach. But that's
    ) precisely what I DID NOT want to do. THat's the beauty and elegance of
    ) map- it operates in 2D.

    No it doesn't. It's just a for loop that returns an array of results.

    This is map, basically:

    sub map (&@) {
    my $func = shift;
    my @result;
    push @result, &$func for @_;
    return @result;
    }

    If you don't use the result of map, then it is *exactly* the same as for.
    (In recent versions of perl, map even checks if it is called in a void
    context, and if so it switches to a for-loop.)


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, May 11, 2010
    #10
  11. Mr P

    Uri Guttman Guest

    >>>>> "TM" == Tad McClellan <> writes:

    TM> Uri Guttman <> wrote:
    >> but i don't think
    >> i will help you until


    TM> You are slow on the uptake :)

    and you just learned this now? :)

    TM> I've been ignoring this poster for years.

    TM> http://groups.google.com/groups/

    yep, same old dog and no new tricks.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, May 11, 2010
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John
    Replies:
    4
    Views:
    1,143
    Vladimir Marko
    May 17, 2005
  2. Replies:
    104
    Views:
    11,028
    Jordan Abel
    Oct 28, 2005
  3. Replies:
    99
    Views:
    2,511
    eliza81
    Jun 11, 2010
  4. Alf P. Steinbach /Usenet
    Replies:
    0
    Views:
    899
    Alf P. Steinbach /Usenet
    May 22, 2011
  5. Peng Yu

    post increment or pre increment?

    Peng Yu, Nov 21, 2008, in forum: Perl Misc
    Replies:
    7
    Views:
    530
    Peter J. Holzer
    Nov 23, 2008
Loading...

Share This Page