in reply to Filtering array of strings and numbers

Hello nysus,

Since you’re testing for equality only, the straightforward solution is to stringify both terms in the comparison, thereby guaranteeing that you always compare a string with a string:

#! perl use strict; use warnings; use Data::Dump; my $string_or_number = 123; my @strings_or_numbers = ('abc', 123, 'ab4', 456); my @filtered = grep { "$string_or_number" ne "$_" } @strings_or_numbe +rs; dd \@filtered;

Output:

1:37 >perl 1612_SoPW.pl ["abc", "ab4", 456] 1:37 >

Of course, this assumes that neither $string_or_number nor any of the elements of @strings_or_numbers are ever undef.

Update: As AnomalousMonk and Laurent_R have pointed out below, the stringwise equality operators eq and ne implicity stringify their operands, so grep { "$string_or_number" ne "$_" } can be simplified to grep { $string_or_number ne $_ }.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: Filtering array of strings and numbers
by stevieb (Canon) on Apr 29, 2016 at 15:46 UTC

    Update: The undef issue that Athanasius pointed out can be avoided by adding a defined check in the grep:

    grep {defined && $string_or_number ne $_} @strings_or_numbers;

    /Update

    ++. This is so elegantly simple it hurts :)

    I was just in a situation the other day where I had to do the same thing as the OP, and it didn't even cross my mind to stringify like that.

    These simple tricks are often the ones that one doesn't think about or forgets about when their head is wrapped around larger problems.

Re^2: Filtering array of strings and numbers
by AnomalousMonk (Archbishop) on Apr 29, 2016 at 16:32 UTC

    Except perhaps for purposes of enhanced readability/maintainability, is the explicit stringification ever needed? Doesn't  ne or any other stringwise comparator implicitly stringify everything it operates on, including references (but with due deference to undef)? (Granted, stringifiying a reference for comparison purposes is usually useless, but that's another discussion.)

    c:\@Work\Perl\monks>perl -wMstrict -le "use warnings; use strict; ;; use Data::Dump qw(dd); ;; my @stuff = ('abc', 123, 'ab4', '123', 456, [ 123 ], { 123 => 'x', x +=> 123 }); ;; my $thing = 123; my @filtered = grep { $thing ne $_ } @stuff; dd \@filtered; ;; $thing = '123'; @filtered = grep { $thing ne $_ } @stuff; dd \@filtered; " ["abc", "ab4", 456, [123], { 123 => "x", x => 123 }] ["abc", "ab4", 456, [123], { 123 => "x", x => 123 }]

    OT: I sometimes see what one might call "super stringification" in code that often seems to originate from biological users, e.g.:
        my $filename = '...';
        open my $fh, '<', "$filename" or die "...";
    Can anyone comment on the origin or history of this apparent (mis-)meme?

    OT: Update: The other odd idiomatic usage I see that seems to be of biological origin is along the lines of:
        my $fh;
        unless (open $fh, ...) {
            print "open failed...";
            exit;
            }
    Huh?!?   Are BioMonks constitutionally averse to die-ing? Is it that  exit; is needed to return a non-error exit code to the OS?


    Give a man a fish:  <%-{-{-{-<

      I had the same reaction. I would think that the ne, eq, etc. string relational operators all coerce their arguments into strings, so that no explicit stringification is needed. But I may miss something.

      Having said that, string comparison operators and arithmetic relational operator don't always return the same thing, so the OP should be aware of that. Remember that 10 is smaller than 3 for string relational operators.

        ... string relational operators all coerce their arguments into string, so that no explicit stringification is needed. But I may miss something.

        The OP uses, and Athanasius's reply explicitly assumes, an equality operator, so I don't think you're missing anything. If you are, I'm missing it too, and I'd be very interested to learn what it is. (Update: Ok, here's something I missed.)

        I agree with you that if you try to use numeric instead of string comparison, you're venturing out onto very thin ice indeed.

        Update: I'm posting this reply again because the first post does not seem to appear in its intended parent thread. I can see the first version of this reply (update: this node) in the history of my posts in my personal node, but there is no link to any parent; it seems to be freely floating somewhere in cyberspace.


        Give a man a fish:  <%-{-{-{-<

Re^2: Filtering array of strings and numbers
by syphilis (Archbishop) on Apr 30, 2016 at 01:49 UTC
    this assumes that neither $string_or_number nor any of the elements of @strings_or_numbers are ever undef

    It also makes other (corner case) assumptions. For example things get a bit dubious when the numbers (barewords) 1.4142135623730951, 1.4142135623730952 and 1.4142135623730953 (on a perl whose NV is double) are subjected to stringwise and numeric comparisons:
    use warnings; my $x = 1.4142135623730951; my $y = 1.4142135623730952; my $z = 1.4142135623730953; print "$x $y $z\n"; $x == $y ? print "x and y are numerically equal\n" : print "x and y are numerically unequal\n"; "$x" eq "$y" ? print "x and y are stringwise equal\n" : print "x and y are stringwise unequal\n"; $z == $y ? print "z and y are numerically equal\n" : print "z and y are numerically unequal\n"; "$z" eq "$y" ? print "z and y are stringwise equal\n" : print "z and y are stringwise unequal\n"; __END__ Outputs: 1.4142135623731 1.4142135623731 1.4142135623731 x and y are numerically equal x and y are stringwise equal z and y are numerically unequal z and y are stringwise equal
    So it makes the assumption that this behaviour is as wanted - which, if you look closely, is rather unlikely.
    Perhaps (not guaranteed) the first two results are as wanted - even though the two barewords are mathematically unequal they do convert to identical doubles and strings.

    But the last 2 results are just bizarre, imo.
    That perl should stringify two different NVs to the same string is rather pathetic - and it happens because perl by default stringifies doubles to only 14 decimal digits. (Update : make that 15, not 14 - the trailing zero for my example values was stripped.)
    If, like in python, the default was 17 decimal digits (as some believe it should be) then the discrepancy of the last 2 results would not arise.
    (We can, of course work around this stringification problem using sprintf, but that just makes it messy.)

    BTW, the same problem arises with perls whose NVs are 'long double' or '__float128'.
    Perl simply does not stringify floating point values to enough decimal digits.

    Cheers,
    Rob
Re^2: Filtering array of strings and numbers
by msh210 (Monk) on May 02, 2016 at 17:36 UTC

    Since you’re testing for equality only, the straightforward solution is to stringify both terms in the comparison, thereby guaranteeing that you always compare a string with a string

    That doesn't work if one number is 0.5 and the other number is the string 0.50. (I mean, it'll show they're unequal when in fact they're equal.) But hopefully you don't have your numbers as strings like that.

    $_="msh210";$"=$\;@_=@{[split//,uc]}[2,0];$_="@_$\1";$\=$/;++$_[0]for$...1;print lc substr crypt($_,"@_"),1,6