http://qs321.pair.com?node_id=525184

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

This will probably seem like an easy concept for some of you and I could surely do it, but I'd like to see a more reasonable approach than what I'd do in this situation.

I have a word that I need to remove characters from. These characters come directly from an array @list. The thing is, IF a character from the array exists in the word, it should be removed from both the word and the array as to not be removed again.

My first thought was breaking apart the word into an array of characters and foreach()'ing over them. I'd then use another foreach() over @list for comparing.

This doesn't seem like a clean approach because I'd have to continually rebuild the @list each time a match is found and character is removed.

I could keep the orginal word as a string and apply s/// for found matches. I feel this might be a slightly better approach.

Can anyone show me what they would do in a situation like this?

Replies are listed 'Best First'.
Re: Removing chars from a word from an array
by murugu (Curate) on Jan 24, 2006 at 15:22 UTC

    Hi,

    I dont know whether i understood your question correctly. If im not wrong what you need is to delete a set of characters from a word. But a character has to be removed only once in the word and has to be removed from @list.

    use strict; use warnings; my @list= qw(a b c a c); my $w="kandabbbc"; while (my $a=shift(@list)) { $w=~s/\Q$a//; @list = grep {!/\Q$a/} @list; } print $w;

    If you want to remove all the occurances of a character from the word, then

    use strict; use warnings; my @list= qw(a b c a c); my $re = join '|', @list; my $w="kandabbbc"; $w=~s/$re//g; print $w;

    Regards,
    Murugesan Kandasamy
    use perl for(;;);

      my @list= qw(a b c a c); my $w="kandabbbc"; while (my $a=shift(@list)) { $w=~s/\Q$a//; @list = grep {!/\Q$a/} @list; } print $w;

      OMG! while and grep to iterate over @list... ok, TMTOWTDI, but then how 'bout a for loop? Also, who told you that @list has duplicates? In any case, if so, then a technique a la'

      my %saw; for (@list) { next if $saw{$_}++; # ... }

      would suffice. Also, don't you think s///g would be better suited to remove chars from his string?

      Incidentally to remove charachters, the best tool would be tr///d a.k.a y///d, but unfortunately it does not interpolate - I don't know if it would be worth to use the usual eval trick to work around this limitation. The OP may still want to know just in case he really knew @list in advance and did not need to delete chars dinamically.

      my @list= qw(a b c a c); my $re = join '|', @list;

      How 'bout using a charachter class instead? That is:

      my $re=join "", @list; $re="[$re]";
Re: Removing chars from a word from an array
by ikegami (Patriarch) on Jan 24, 2006 at 16:05 UTC

    Let's try this again!

    my $word = 'abracadabra'; my @list = qw( a b c d e ); my %list = map { $_ => 1 } @list; foreach (@list) { delete $list{$_} if $word =~ s/\Q$_//; } @list = keys %list; print("remaining word: ", $word, "\n"); # raaabra print("remaining list: ", @list, "\n"); # e
    outputs
    remaining word: raaabra remaining list: e

    If you wish to replace all intances of the characters in @list, replace s/\Q$_// with s/\Q$_//g. The output would then be the following for the above snippet:

    remaining word: rr remaining list: e
Re: Removing chars from a word from an array
by Roy Johnson (Monsignor) on Jan 24, 2006 at 21:58 UTC
    I especially like the use of !~ with s/// here. I thought the use of hashes for this was overkill.
    my $word = 'committee'; my @list = qw( t r e e ); @list = grep $word !~ s/\Q$_//, @list; print "W=$word, L=(@list)\n";

    Caution: Contents may have been coded under pressure.
Re: Removing chars from a word from an array
by ikegami (Patriarch) on Jan 24, 2006 at 14:55 UTC
    for my $i (0..$#array) { $array[$i] =~ s/x//g; }
    Or take advantage of the fact that foreach aliases the counter variable to the actual element of the list with the following:
    foreach (@array) { s/x//g; }
    That can also be written as
    s/x//g foreach @array;

    Update: Due to distractions, I incorrectly read the OP's question.

Re: Removing chars from a word from an array
by Not_a_Number (Prior) on Jan 24, 2006 at 21:09 UTC

    I might have missed something, but what about:

    $word =~ s/$_// for @list;

    ?

Re: Removing chars from a word from an array
by GrandFather (Saint) on Jan 24, 2006 at 21:35 UTC

    Parts of the following may get you where you want to go:

    use strict; use warnings; my $word = 'committee'; my @list = qw(t r e e); my %remove; $remove{$_}++ for @list; for my $letter (keys %remove) { --$remove{$letter} while $remove{$letter} and $word =~ s/$letter// +; } #rebuild list @list = (); for my $letter (keys %remove) { push @list, $letter while $remove{$letter}--; } print "Edited word: $word\nEdited list: @list";

    Prints:

    Edited word: commit Edited list: r

    DWIM is Perl's answer to Gödel
Re: Removing chars from a word from an array
by superfrink (Curate) on Jan 25, 2006 at 03:56 UTC
    Update:murugu already posted this solution and blazar suggested using a character class in the regex.

    #!/usr/bin/perl -w use strict; # input from ikegami my $word = 'abracadabra'; my @list = qw( a b c d e ); my $pattern = join("|" , @list); print "pattern: $pattern\n\n"; print "before: $word\n"; $word =~ s/$pattern//g; print "after : $word\n";