Re: String comparison in an array
by haukex (Archbishop) on Aug 08, 2018 at 12:44 UTC
|
grep { $elements[0] eq '$_' }@keys is it something to do with string comparison with quotes and no quotes?
Yes, because single quotes don't interpolate variables - '$_' means "the string consisting of the two characters $ and _". "$_" would interpolate the variable into the string. Note that if @keys contains only strings, you can just say grep { $elements[0] eq $_ } @keys, without the quotes.
Also, note that grepping an array like this is usually less efficient than using a hash. For example, you can say my %keyhash = map {($_=>1)} @keys; and this will create a hash where the keys are the elements of the @keys array, and the values are all 1. Then, to check if an element is contained in @keys/%keyhash, you just need to say if ($keyhash{$elements[0]}) ....
Update: The trick with creating a hash that makes it more efficient is of course to only do it once, above any loops. Also, as a side note, there is first from List::Util, that is like grep but stops when it finds the first match (but depending on the data it's likely still slower than a hash).
| [reply] [d/l] [select] |
|
|
sure,thanks,but with hash too the comparison is not working, probably because $element[0] is coming with double quotes "computer" and the strings in the array/hash do not.....how to get rid of this, this is coming from the split statement
| [reply] |
|
|
| [reply] |
|
|
| [reply] |
Re: String comparison in an array
by Eily (Monsignor) on Aug 08, 2018 at 12:43 UTC
|
You can add some debug information in your grep while testing, like this:
grep {
print $elements[0], '$_', "\n";
$elements[0] eq '$_'
}
@keys;
The issue is that simple quotes prevent interpolation (ie, perl will keep the content unmodified). A bare $_ should do the trick | [reply] [d/l] |
|
|
In addition to all other suggestions, I recommend that you use the function "any" (from List::Utils) rather than grep. The name makes your intention clear. It can also be slightly faster because it shortcuts after the first match.
| [reply] |
|
|
thanks, but bare $_ also did not work
printing them gives this :
$elements[0] = "computer"
$_ = computer
| [reply] |
|
|
Ah right, it really looks like you are trying to read a csv file. You should consider using Text::CSV as it already handle special cases (values with quotes among values without, multiline values etc...). Beyond that you can follow hippo's advice
| [reply] |
|
|
|
|
|
Re: String comparison in an array
by LanX (Saint) on Aug 08, 2018 at 13:18 UTC
|
Please provide some sample data to reproduce your problem.
| [reply] |
|
|
use strict;
use warnings;
use Data::Dump;
use Text::CSV;
use List::MoreUtils qw{ any };
my $first = 'computer';
my $last = 'printer';
my $in = 0;
my @keys;
open DATA, "types.txt" or die $!;
while (<DATA>)
{
if (defined(my $key = (split)[-5]))
{
if ($key eq $first .. $key eq $last)
{
$in = 1;
push @keys, $key;
}
elsif ($in && $key eq $last)
{
push @keys, $key;
}
else
{
$in = 0;
}
}
}
dd @keys;
my $filename = "orders.csv";
my $csv = Text::CSV->new ( { binary => 1 } );
open my $fh, "<:encoding(Latin-1)", "orders.csv" or die "Cannot open $
+ +filename";
my $do_skip_test = 1;
my %keyhash = map {($_=>1)} @keys;
while(my $line = <$fh>)
{
if ($do_skip_test)
{
my (@fillarr1) = split ';',$line;
#print $fillarr1[14];
#if ((grep { print $fillarr1[14], $_,"\n";$fillarr1[14] eq $_
++}@keys))
#need to change this loop to compare all array variables
#if (($fillarr1[14] =~ /tm_C40_ANA_v1.12.0/) || ($fillarr1[14]
+ + =~ /tm_C40_ANA_v1.14.0/))
#if (exists $fillarr1{$fillarr1[14]})
#if ($keyhash{$fillarr1[14]})
if (($fillarr1[14] =~ /$_/)@keys)
{
#$do_skip_test = 0;
my (@fillarr) = split ';',$line;
print "\n$fillarr[0]\t$fillarr[1]\t$fillarr[3]\t$fillarr[4
+ +]\t$fillarr[5]\t$fillarr[14]\t";
}
else
{
next;
}
}
}
close($fh);
| [reply] [d/l] |
|
|
| [reply] |