无法从PERL中的数组中提取特定值(变量)

时间:2015-08-22 01:32:54

标签: perl

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,

我想提取(column 6) value if (column 3 = 09:00:00)

推送到$result变量。这需要是特定值/变量而不是数组。我需要使用该值进行其他计算并将其移动到数据库。这是我使用的代码,但我无法将特定值提取到变量。

 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>;

当我试图减去或做其他数学时,这些数字是荒谬的。

3 个答案:

答案 0 :(得分:1)

map总是有一对一的映射,如果你输入10个东西,你将得到10个东西的列表。你想要的是一个有选择地推入数组的while循环。

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,

从您的变量名称@temp_9@t_fh_9,我怀疑您在特定时间内对变量名称进行了硬编码。这将导致大量代码重复。相反,写一个小功能,花时间你正在寻找。

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');

最后,我猜你会在不同时间获取数据。这将导致一堆变量,这些变量作为一个整体难以传递。不是每次都有变量,而是将每个列表放入哈希值。

my $time = '09:00:00'; 
$extracts{$time} = [extract_column_for_time_of_day(\*DATA, 6, $time)];

答案 1 :(得分:1)

似乎混淆的一个原因是从数组中提取元素。数组是零个或多个标量元素 - 你不能只将一个元素分配给另一个元素,因为......好吧,如果不存在一个元素(通常情况下)会发生什么。

给定一个数组,我们可以:

  • pop @array将返回最后一个元素(并将其从数组中删除),以便您my $result = pop @array;
  • [0]是数组的第一个元素,因此我们可以my $result = $array[0];
  • 或者我们可以将一个数组分配给另一个:my ( $result ) = @array; - 因为在左侧我们现在有一个数组,它是一个单一元素 - @array的第一个元素进入$result。 (其余部分未在此方案中使用 - 但您可以执行my ( $result, @anything_else ) = @array;

因此,在您的示例中 - 如果您尝试执行的操作是检索符合条件的值,则该作业的常规工具将是grep - 它通过应用条件测试来过滤数组每个元素。

所以:

#!/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

我们可以减少到:

my ( $firstresult ) = grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print $firstresult;

但是因为我们想要转换我们的数组 - map是工作的工具。

my ( $result ) = map { (split /,/)[6] - 273.15 } grep { (split /,/)[2] eq "12:00:00" } <DATA>;
print $result;

首先我们:

  • 使用grep提取匹配元素。 (在这种情况下,一个,但不一定非必须!)
  • 使用map来变换列表,以便我们将每个元素转换为它的第6个字段,并减去273.15
  • 将整个批次分配到包含单个元素的列表 - 实际上只是取第一个结果,然后抛弃其余部分。

或者也许:

#!/usr/bin/env perl
use strict;
use warnings;

my ($result) = map {
          ( split /,/ )[2] eq "12:00:00"
        ? ( split /,/ )[6] - 273.15
        : ()
} <DATA>;
print $result;

但就个人而言,我认为这有点复杂,可能很难理解。 map是一个功能强大的功能,但可能会导致代码难以阅读以供将来的维护程序员使用。

所以我建议改为:

my $result;
while (<DATA>) {
    my @fields = split /,/;
    if ( $fields[2] eq "12:00:00" ) {
        $result = $fields[6] - 273.15;
        last;
    }
}

print $result;

迭代您的数据,拆分 - 并测试 - 每一行,当您找到符合条件的行时,设置$result并保释出循环。

答案 2 :(得分:0)

map函数通常会返回一个列表,其中包含与源相同数量的元素,除非返回空元素或多元素列表。实际上,map perl doc中的第一个示例之一显示了如何执行此操作,再次证明您应该首先检查文档。

my @temp_9 = map {
    chomp;
    my @t_fh_9 = split /,/;
    $t_fh_9[2] eq '09:00:00' ? ( $t_fh_9[6] ) : ();
} <$ft1>;