Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

How to make sure no elements from @array are inside $scalar

by Steffen (Novice)
on Nov 14, 2014 at 09:57 UTC ( [id://1107187]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Perl Monks,

I have a list of values inside an array. Now I want to check if none of the values inside the array are part of my scalar (at a certain position). Here's what I have so far:

use strict; my $text = 'f000124_90181234_dp'; my $sites = [ '018', '324' ]; my $deleteme = 1; if (grep {$text =~ /_9$_/} @$sites) { $deleteme = 0 } if ($deleteme) { print "To be removed..\n" }

Note: The array (@$sites) can be of variable length.


The code basically works; question is how can this be coded more elegant? It somehow looks kind of awkward to me ;)


Thanks for any advice!
BR
Steffen

Replies are listed 'Best First'.
Re: How to make sure no elements from @array are inside $scalar
by McA (Priest) on Nov 14, 2014 at 10:15 UTC

    Hi,

    IMHO it's ok. I have three annotations:

    If the array referred by $sites is used more than once, you could think about concatenating '_9' before doing the match.

    You want to delete the item as soon as one pattern matches. Therefore you can shortcut the grep with using List::Util::any.

    You could try to match against a regex which is build from the elements of the list.

    my $regex = '_9(?:' . join('|', map { quotemeta } @$sites) . ')'; $text =~ /$regex/;

    Regards
    McA

Re: How to make sure no elements from @array are inside $scalar
by pme (Monsignor) on Nov 14, 2014 at 11:21 UTC
    Hi Steffen,

    A possible more elegant way:

    use strict; my $text = 'f000124_90181234_dp'; my $sites = [ '018', '324' ]; if (grep {$text =~ /_9$_/} @$sites) { print "To be removed..\n"; }
Re: How to make sure no elements from @array are inside $scalar
by Loops (Curate) on Nov 14, 2014 at 14:14 UTC

    Lots of ways to tackle it. Here's one that's too convoluted...

    my $text = 'f000124_90181234_dp'; my $sites = [ '018', '324' ]; print "$text To be removed" unless $text=~/_9(...)/,{map{$_,1}@$sites}->{$1};

    But using List::Util is better.

    use List::Util qw(none); print "$text To be removed" if $text=~/_9(...)/,none {$1 eq $_} @$sites;

      Can I use

       $text=~/_9(...)/ and none {$1 eq $_} @$sites

      instead of

       $text=~/_9(...)/,none {$1 eq $_} @$sites

      here ?

      What's the difference between 'and' and 'comma' here

        Yes, you can use "and" to much the same effect in this case. In fact it would stop a warning if the match failed and $1 was left undefined. And that's because the comma operator does not short circuit as "and" does; both expressions will be evaluated whether the first is true or false. But it can be useful.

Re: How to make sure no elements from @array are inside $scalar
by Anonymous Monk on Nov 14, 2014 at 11:30 UTC
    A bit more elegant, IMO:
    use strict; use warnings; use List::Util qw( any ); my $text = 'f000124_90181234_dp'; my $sites = [ '018', '324' ]; sub delete_me { my ( $str, $aref, $anchor ) = @_; return any { index( $str, $anchor . $_ ) != -1 } @$aref; } if ( delete_me( $text, $sites, '_9' ) ) { print "To be removed...\n"; }
      (oops, it seems you want to delete if nothing matches. Just replace 'any' with 'none' then)
Re: How to make sure no elements from @array are inside $scalar
by AnomalousMonk (Archbishop) on Nov 14, 2014 at 15:14 UTC

    Note that while functions like any(), none() and a few others are currently a part of the List::Util core module, they were originally found in List::MoreUtils and only relatively recently merged into the former module. For instance, in my Strawberry Perl 5.14, those functions are still only found in the latter module. (I haven't taken the trouble to find when the merger happened.)

      As it wasn't any trouble at all, I've done it for you. ;)

      The Change Log gives the import date as "Sun Oct 13 01:35 UTC 2013" which was version 1.33.

Re: How to make sure no elements from @array are inside $scalar
by GotToBTru (Prior) on Nov 14, 2014 at 13:56 UTC

    For matching at a specific position, no need to use regex, just substr.

    1 Peter 4:10
Re: How to make sure no elements from @array are inside $scalar
by Steffen (Novice) on Nov 14, 2014 at 15:28 UTC

    Wow, thanks to all for your responses! Again learned a lot by reading through your answers. I think in the end it's a matter of taste, I personally like the List::Utils way best. Also new to me was the comma operator - really handy!

    if ($text =~ /_9(...)/, none {$1 eq $_} @$sites) { print "To be remove +d..\n" }
      Notice that your chosen solution will only use the first match in $text that starts with '_9', so it won't work with something like 'f000124_9019_90181234_dp'.
      use List::Util qw( none ); my $text = 'f000124_9019_90181234_dp'; my $sites = [ '018', '324' ]; if ($text =~ /_9(...)/, none {$1 eq $_} @$sites) { print "$1 doesn't match anything: to be removed..\n" }
      Output:
      019 doesn't match anything: to be removed..
      This isn't how your original code worked.

        Yes you're perfectly right, thanks for mentioning it. However I haven't told that the strings I need to check have a rather static format of:

        <userid>_<8-digit-number-starting-with-9>_dp

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1107187]
Approved by Corion
Front-paged by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2024-04-23 10:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found