ler224 has asked for the wisdom of the Perl Monks concerning the following question:
How can I avoid this warning when working with blank fields? I am trying to get the count of lines with successful cases (1,1) and lines with failed cases (1,2).
Data Structure
1,1,,,,
1,2,,,,
3,4,1,1,,
1,1,1,1,,
5,6,3,4,1,2
1,1,,,,
1,1,1,1,1,1
#Success & Fail
if((($f[1]==1)&&($f[2]==1))||(($f[3]==1)&&($f[4]==1))||(($f[5]==1)&&
+($f[6]==1))) {
$success = 1;
}else{
$success = 0;
}
if((($f[1]==1)&&($f[2]==2))||(($f[3]==1)&&($f[4]==2))||(($f[5]==1)&&
+($f[6]==2))) {
$fail = 1;
}else{
$fail = 0;
}
Re: Argument "" Isn't numeric in numeric eq (==)
by choroba (Cardinal) on Feb 09, 2014 at 15:49 UTC
|
The following code returns the same results as yours, but no warnings. In my eyes, it is even more readable.
my ($success, $fail) = (0, 0);
for my $i (0 .. @f / 2) {
if (($f[1 + $i * 2] || 0) == 1) {
$success = 1 if ($f[$i * 2 + 2] || 0) == 1;
$fail = 1 if ($f[$i * 2 + 2] || 0) == 2;
}
}
| [reply] [d/l] |
|
This looks really cool. But how did you manage it before?
Imho it looks like CSV and the OP needs to do something like my @f = split ',', $data;.
This yields:
$VAR1 = [
'1',
'1'
];
And after casting it:
$VAR1 = [
1,
1
];
What do i miss (or perhaps yet another mental block)?
Best regards, Karl
«The Crux of the Biscuit is the Apostrophe»
| [reply] [d/l] [select] |
|
I do not understand the question. I just populated the @f array as in the OP. I just used
while (<DATA>) {
my @f = (undef, split /,/);
as the @f in the OP is not zero based, but one based. There is no need to cast between strings and numbers in Perl.
| [reply] [d/l] |
|
|
Re: Argument "" Isn't numeric in numeric eq (==)
by RMGir (Prior) on Feb 09, 2014 at 15:49 UTC
|
You could just disable warnings, but why not say what you intend?
If you want blank entries to be 0, just make them so:
# Consider all blank entries to be 0.
foreach (@f) {
$_ = 0 unless length $_;
}
After that, all your ""'s become zeros, and == will behave just fine.
| [reply] [d/l] |
Re: Argument "" Isn't numeric in numeric eq (==)
by CountZero (Bishop) on Feb 09, 2014 at 15:31 UTC
|
I think this is a good example where you can locally switch off warnings. You can of course also add tests that check (with eq rather than ==) if any field is blank, but that only complicates the logic for no good reason.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James My blog: Imperial Deltronics
| [reply] [d/l] [select] |
|
Yes I tried using eq, but the logic was getting too complex.
| [reply] |
|
But did you try simply switching off warnings (in a suitably narrow scope, of course)? I.e.,
no warnings;
or
no warnings qw(numeric);
See warnings and perllexwarn.
| [reply] [d/l] [select] |
Re: Argument "" Isn't numeric in numeric eq (==)
by wjw (Priest) on Feb 09, 2014 at 17:38 UTC
|
I just did the following while playing around with this. There is a lot to be desired regarding elegance and
efficiency, but for the cases you see in @all, it works. Assumptions are that there will never be a "0"(zero)
value in any position, that your data will always have an even number of test values in each test case(3 per line?).
I had though that the 'defined' function would work, but it does not. Also, in the cases where there are empty values
in your data following defined values, the array does not even pick the empty values up. The case where the first test
value pair in the line are blank (,,1,2,,), is what makes the matching necessary down in the while loop. Those first two
values actually come in as empty strings...
#!/usr/bin/perl
use strict;
use warnings;
my (@all,$line,$fail,$success,$f,$s,$lc,$sc);
push(@all, "1,1,,,,");
push(@all, "3,4,1,1,,");
push(@all, "1,1,1,1,,");
push(@all, "5,6,3,4,1,2");
push(@all, "1,1,1,1,1,1");
push(@all, "1,2,,,,");
push(@all, ",,1,2,,");
$lc = 0; #line count
$sc = 0; #success count
foreach $line (@all) {
my @data = split(",", $line);
$lc ++;
$f = 0;
$s = 1;
while ($f < (scalar @data)) {
if ($data[$f] !~ m/[0-9]/) {
$f = $f + 2;
$s = $s + 2;
next;
};
if ($data[$s] !~ m/[0-9]/) {
$f = $f + 2;
$s = $s + 2;
next;
};
if ($data[$f] + $data[$s] != 2) {
$fail = 1;
$success = 0;
} else {
$success = 1;
$fail = 0;
$sc ++;
print "Line $lc contains a success, $sc successes found th
+us far...\n"
}
$f = $f + 2;
$s = $s + 2;
}
}
Hope this is of some use to you... it sure ain't pretty... lol...
...the majority is always wrong, and always the last to know about it...
Insanity: Doing the same thing over and over again and expecting different results.
| [reply] [d/l] |
Re: Argument "" Isn't numeric in numeric eq (==)
by Jim (Curate) on Feb 09, 2014 at 19:07 UTC
|
use strict;
use warnings;
my $success_pattern = qr/^(?:\d?,\d?,){0,2}1,1/;
my $failure_pattern = qr/^(?:\d?,\d?,){0,2}1,2/;
my $count_of_success_records = 0;
my $count_of_failure_records = 0;
while (my $record = <DATA>) {
$count_of_success_records++ if $record =~ $success_pattern;
$count_of_failure_records++ if $record =~ $failure_pattern;
}
print "Total success records: $count_of_success_records\n";
print "Total failure records: $count_of_failure_records\n";
exit 0;
__DATA__
1,1,,,,
1,2,,,,
3,4,1,1,,
1,1,1,1,,
5,6,3,4,1,2
1,1,,,,
1,1,1,1,1,1
| [reply] [d/l] [select] |
Re: Argument "" Isn't numeric in numeric eq (==)
by kcott (Archbishop) on Feb 10, 2014 at 04:56 UTC
|
G'day ler224,
Firstly, some issues I had with your question:
-
What you show as a "Data Structure" is just text: I've guessed it's an array of arrays.
-
While you don't actually show @f, your code has $f[1], $f[2], etc. which reinforces my guess of an array.
-
In Perl, array indices are zero-based.
The code you show has no $f[0].
I don't know if that's an error on your part or if there's some other data that you haven't shown.
Here's a technique that uses my array of arrays assumption: you can probably modify it for some other data structure (or to take unshown data into account) if my assumption is wrong.
You'll see there's no constraint that the inner arrays must have six elements nor additional code targetting specific indices.
This is intended to both reduce the amount of code you need to write (and maintain) as well as allowing the number of elements to be modified at some future time without requiring changes to the code.
Also note I've added four more test cases: [2,3] (contains neither success or fail cases); [1,1,1,2] (contains both success and fail cases); [] (contains no cases at all); and, [3,2,1] (bad data - odd number of elements).
#!/usr/bin/env perl -l
use strict;
use warnings;
my @data = (
[1,1,,,,],
[1,2,,,,],
[3,4,1,1,,],
[1,1,1,1,,],
[5,6,3,4,1,2],
[1,1,,,,],
[1,1,1,1,1,1],
[2,3],
[1,1,1,2],
[],
[3,2,1],
);
my %lines_with = (success => 0, fail => 0);
for my $line (@data) {
my ($success, $fail) = (0, 0);
while (@$line) {
my ($first, $second) = splice @$line, 0, 2;
next unless defined $first && $first == 1;
next unless defined $second;
++$success if $second == 1;
++$fail if $second == 2;
}
++$lines_with{success} if $success;
++$lines_with{fail} if $fail;
}
print "Lines with successes: $lines_with{success}";
print "Lines with fails: $lines_with{fail}";
Output:
Lines with successes: 6
Lines with fails: 3
| [reply] [d/l] [select] |
|
I agree that ler224's OP is no more than a hint of a suggestion of a specification, but the only way I can see to get an array containing empty strings from something like 1,1,,,, is if it's a string '1,1,,,,' that's been subjected to some kind of split operation. If 1,1,,,, is a list literal, all those commas flatten to nothing.
c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le
"my @ra = ([1,1], [1,1,,,,], [1,1,,,,,,,,,,,,]);
dd \@ra;
"
[[1, 1], [1, 1], [1, 1]]
| [reply] [d/l] [select] |
|
While I don't disagree with you, I think we could guess at the data structure and missing code until the cows come home and still get it wrong.
My intent was really just meant to provide an idea of how the task might be tackled:
"Here's a technique ... you can probably modify it ..."
[I also note that it's more than a day and half since the OP was posted and, despite a number of replies raising issues with it, ler224 has provided no clarification whatsoever.]
| [reply] |
|
Re: Argument "" Isn't numeric in numeric eq (==)
by Kenosis (Priest) on Feb 09, 2014 at 20:31 UTC
|
Consider using a regex that captures sets of two digits (or 'empties') separated by a comma, as tuples:
use strict;
use warnings;
while ( my $line = <DATA> ) {
print +( join ',', map "($_)", $line =~ /(\d*,\d*),?/g ), "\n";
}
__DATA__
1,1,,,,
1,2,,,,
3,4,1,1,,
1,1,1,1,,
5,6,3,4,1,2
1,1,1,1,1,1
,,,,1,1
,,1,2,,
,,1,1,1,2
,,,,,
5,6,3,4,2,2
Output:
(1,1),(,),(,)
(1,2),(,),(,)
(3,4),(1,1),(,)
(1,1),(1,1),(,)
(5,6),(3,4),(1,2)
(1,1),(1,1),(1,1)
(,),(,),(1,1)
(,),(1,2),(,)
(,),(1,1),(1,2)
(,),(,),(,)
(5,6),(3,4),(2,2)
And then testing for '1,1' and '1,2' in each line:
use strict;
use warnings;
my ( $i, $success, $fail );
while ( my $line = <DATA> ) {
$i++;
my %tuples = map { $_ => 1 } $line =~ /(\d*,\d*),?/g;
$success++ if exists $tuples{'1,1'};
$fail++ if exists $tuples{'1,2'};
}
print "Total Lines: $i\nSuccess: $success\nFail: $fail\n";
__DATA__
1,1,,,,
1,2,,,,
3,4,1,1,,
1,1,1,1,,
5,6,3,4,1,2
1,1,1,1,1,1
,,,,1,1
,,1,2,,
,,1,1,1,2
,,,,,
5,6,3,4,2,2
Output:
Total Lines: 11
Success: 6
Fail: 4
BTW - You were off by one in all of your array indices. You had:
if((($f[1]==1)&&($f[2]==1))|| ...
when you meant:
if((($f[0]==1)&&($f[1]==1))|| ...
Hope this helps!
Edit: Updated to reflect the '1,2' "Fail" condition, which I failed to notice. Thank you, Jim. | [reply] [d/l] [select] |
Re: Argument "" Isn't numeric in numeric eq (==)
by Anonymous Monk on Feb 10, 2014 at 00:33 UTC
|
Match 1,1 or 1,2 after an even number of commas:
my $tuple = qr/\d*,\d*,/;
while (<DATA>) {
print "pass: $_" if /^$tuple*1,1\b/;
print "fail: $_" if /^$tuple*1,2\b/;
}
| [reply] [d/l] [select] |
Re: Argument "" Isn't numeric in numeric eq (==)
by Not_a_Number (Prior) on Feb 09, 2014 at 21:27 UTC
|
I am trying to get the count of lines with successful cases (1,1) and lines with failed cases (1,2).
Not enough information:
- Is 112 a success or a fail (and why)?
- Do the tuples (1,1) and (1,2) have to be contiguous (is 13167 a success or a fail)?
- Does order matter (is 2115 a success or a fail)?
| [reply] |
|
1,1,,,,
1,2,,,,
3,4,1,1,,
1,1,1,1,,
5,6,3,4,1,2
1,1,,,,
1,1,1,1,1,1
the code indicates that "Success" obtains when at least one of the following tuples is '1,1' and "Fail" obtains when one is '1,2':
(n,n),(n,n),(n,n)
^ ^ ^
| | |
| | + - Tuple 3
| + - Tuple 2
+ - Tuple 1
Edit: Added the "Fail" condition. Thank you, Jim. | [reply] [d/l] [select] |
|
Read the OP again. There's both a "success case" (1,1) and a "fail case" (1,2), and they're independent. There's nothing in the specification of the problem that precludes the possibility of both a success case and a fail case in the same three-tuple record. As it happens, there isn't an example in the OP of a record that has both a success case and a fail case in it. So the record ,,,,, has neither a success case nor a fail case in it, and the record 1,1,1,2,1,2 has one success case and two fail cases in it. However, the specification is to count the number of records that have success cases and fail cases in them, not the number of such cases.
| [reply] [d/l] [select] |
Re: Argument "" Isn't numeric in numeric eq (==)
by Bloodnok (Vicar) on Feb 10, 2014 at 15:15 UTC
|
Why not iterate over the data set, a line at a time, using a regex to capture all required occurrences...
$ perl -e 'my $t = "1,2,3,4,1,1,1,3,5,1,1,1,1"; my @s = $t =~ /(1,1),?/g; my @f = $t =~ /(1,2),?/g; die sprintf "%d success(es), %d failure(s)", scalar @s, scalar @f' returns 3 success(es), 1 failure(s) at -e line 1 ... as expected - with no warnings :-)
A user level that continues to overstate my experience :-))
| [reply] [d/l] [select] |
|
|