Reputation: 143
DATA FILE temp.csv
1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,
2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,
3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,
4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,
5,2015-08-20,12:00:00,77,1004.96,298.034,298.87,
I want to extract (column 6) value if (column 3 = 09:00:00)
push to $result
variable. This needs to be the specific value/variable not an array. I need to do additional calculations with that value and move it to a database. Here is the code I used but I can't extract the specific value to a variable.
my @temp_9 = map {
chomp;
my @t_fh_9 = split /,/;
sprintf "%.0f", $t_fh_9[6] if $t_fh_9[2] eq '09:00:00';
} <$ft1>;
When I attempt to subtract or do other math the numbers are nonsensical.
Upvotes: 0
Views: 175
Reputation: 164699
map
always has a one to one mapping, if you put 10 things in, you will get a list of 10 things out. What you want is a while loop which selectively pushes onto an array.
use strict;
use warnings;
use v5.10;
my @nines;
while(<DATA>) {
chomp;
my @row = split /,/;
next unless $row[2] eq '09:00:00';
push @nines, sprintf("%.0f", $row[6]);
}
say join ", ", @nines;
__DATA__
1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,
2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,
3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,
4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,
5,2015-08-20,12:00:00,77,1004.96,298.034,298.87,
From your variable names like @temp_9
and @t_fh_9
, I suspect you're hard coding the variable name with the particular time of day. This will lead to a lot of code duplication. Instead, write a little function that takes the time of day you're looking for.
sub extract_column_for_time_of_day {
my($fh, $column_number, $time_of_day) = @_;
my @extracts;
while(<$fh>) {
chomp;
my @row = split /,/;
next unless $row[2] eq $time_of_day;
push @extracts, sprintf("%.0f", $row[$column_number]);
}
return @extracts;
}
say join ", ", extract_column_for_time_of_day(\*DATA, 6, '09:00:00');
Finally, I'm guessing you're going to get data for various times. This will lead to a pile of variables which will be awkward to pass around as a unit. Instead of having a variable for each time, put each list into a hash.
my $time = '09:00:00';
$extracts{$time} = [extract_column_for_time_of_day(\*DATA, 6, $time)];
Upvotes: 1
Reputation: 53478
It seems one of the sources of confusion is extracting an element from an array. An array is zero or more scalar elements - you can't just assign one to the other, because .... well, what should happen if there isn't just one element (which is the usual case).
Given an array, we can:
pop @array
will return the last element (and remove it from the array) so you could my $result = pop @array;
[0]
is the first element of the array, so we can my $result = $array[0];
my ( $result ) = @array;
- because on the left hand side we have an array now, and it's a single element - the first element of @array
goes into $result
. (The rest isn't used in this scenario - but you could do my ( $result, @anything_else ) = @array;
So in your example - if what you're trying to do is retrieve a value matching a criteria - the normal tool for the job would be grep
- which filters an array by applying a conditional test to each element.
So:
#!/usr/bin/env perl
use strict;
use warnings;
my @lines = grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print "@lines";
print $lines[0];
__DATA__
1,2015-08-20,00:00:00,89,1007.48,295.551,296.66,
2,2015-08-20,03:00:00,85,1006.49,295.947,296.99,
3,2015-08-20,06:00:00,86,1006.05,295.05,296.02,
4,2015-08-20,09:00:00,85,1005.87,296.026,296.93,
5,2015-08-20,12:00:00,77,1004.96,298.034,298.87
Which we can reduce to:
my ( $firstresult ) = grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print $firstresult;
But as we want to want to transform our array - map
is the tool for the job.
my ( $result ) = map { (split /,/)[6] - 273.15 } grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print $result;
First we:
Or perhaps:
#!/usr/bin/env perl
use strict;
use warnings;
my ($result) = map {
( split /,/ )[2] eq "12:00:00"
? ( split /,/ )[6] - 273.15
: ()
} <DATA>;
print $result;
But personally, I think that's getting a bit complicated and may be hard to understand. map
is a powerful function, but can lead to code that's hard to read for future maintenance programmers.
So I would suggest instead:
my $result;
while (<DATA>) {
my @fields = split /,/;
if ( $fields[2] eq "12:00:00" ) {
$result = $fields[6] - 273.15;
last;
}
}
print $result;
Iterate your data, split - and test - each line, and when you find one that matches the criteria - set $result
and bail out of the loop.
Upvotes: 1
Reputation: 2297
The map
function typically returns a list with the same number of elements as the source, unless you return an empty or multi-element list. In fact, one of the first examples in the map
perl doc's shows how to do this, once again proving you should always check the docs first.
my @temp_9 = map {
chomp;
my @t_fh_9 = split /,/;
$t_fh_9[2] eq '09:00:00' ? ( $t_fh_9[6] ) : ();
} <$ft1>;
Upvotes: 0