2015-08-22 3 views
0

DATA FILE temp.csvНевозможно извлечь конкретное значение (переменной) из массива в PERL

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

Когда я пытаюсь вычесть или выполнять другую математику, цифры являются бессмысленными.

+2

Ваш пример кода сравнивает столбец с символом «9: 00: 00' - отсутствует недостающий начальный ноль в вашей паре или вашем коде? –

+0

typo - выше работает, но проблема остается в виде массива – BrianB

+1

Не используйте 'map', если вы хотите' grep'. –

ответ

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 для извлечения совпадающих элементов. (один в этом случае, но необязательно должен быть!)
  • используйте карту, чтобы преобразовать список, чтобы мы превратили каждый элемент в его 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 и выручать из цикла.

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)]; 
+0

* «Карта» всегда имеет одно к одному отображение, если вы поместите 10 вещей, вы получите список из 10 вещей »* вводит в заблуждение, поскольку tose * things * может быть многоэлементным списком или пустым списком. 'map {$ _> 2? ($ _, $ _, $ _):()} 1, 2, 3, 4' генерирует шестиэлементный список '3, 3, 3, 4, 4, 4' – Borodin

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

« my ($ result) = map "от Sobrique был синтаксис, который спас день. Массив убивал меня, хотя он производил желаемое значение при первом румянце, я не мог использовать эту переменную в дальнейших вычислениях или функциях. Вышеупомянутый синтаксис дал мне такую ​​необходимую гибкость. Спасибо всем за вашу помощь и спасибо Sobrique. – BrianB

Смежные вопросы