2015-01-01 2 views
1

Я пытаюсь распечатать столбцы из данных, используя значение ключа индекса во внешней части цикла foreach.Как распечатать конкретный столбец из табличных данных

my @col; 
foreach(<DATA>){ 
    @x = split(' ',$_); 
@xz = ($x[0],$x[1],$x[2]) ; 
    #print "$x[0]\n"; This is working but i'm not expect this. 
push(@col,@xz); 
} 
print "$col[0]\n"; 
__DATA__ 
7  2  3 

3  2  8 

6  7  2 

Я ожидаю, что выход

7 3 6 

Как я могу это сделать?

ответ

2
my @col; 
while (<DATA>) { 
    push @col, (split ' ')[0]; 
    # push @col, /(\S+)/; # split alternative 
} 
print "@col\n"; 

__DATA__ 
7  2  3 

3  2  8 

6  7  2 

выход

7 3 6 
-1

Вы были очень близки, я думаю. Это то, что я сделал (отредактирован, чтобы отразить комментарии @Borodin):

use strict; 
use warnings; 

sub getColumn { 
    my ($data, $col) = @_; 
    my @output = map $_->[$col], @{$data}; 
    return @output; 
} 

my @data; 
while (<DATA>){ 
    push(@data, [split(' ',$_)]); 
} 
print join(' ', getColumn(\@data, 0), "\n"); 
print join(' ', getColumn(\@data, 1), "\n"); 
print join(' ', getColumn(\@data, 2), "\n"); 

__DATA__ 
7  2  3 
3  2  8 
6  7  2 

Это подпрограмма getColumn должна позволить вам получить любой произвольный столбец. Когда я запустил его с данными, которые я получил для вывода:

7 3 6 
2 2 7 
3 8 2 
+0

@RonBergin Хороший улов, спасибо! – rchang

+1

Я бы также очистил эти печатные заявления. Если вы не возражаете, я отредактирую ваше сообщение с этим обновлением. –

+1

Ваша программа не будет компилироваться, поскольку она не существует, потому что нет 'say' без функции использования say'' или' use 5.010' или аналогичной. Вы действительно должны «использовать строгие» и «использовать предупреждения» на месте. Есть ли причина, по которой вы использовали 'for' вместо' while' для чтения файла? И подпрограмма 'getColumn' не нужна. Если вы действительно хотите сохранить его, тогда его можно записать 'map $ _-> [$ col], @ {$ data}'. – Borodin

3

Всегда используйте use strict; и use warnings; !!

У вас есть несколько вопросов:

push(@col, @xz); 

В этом случае, вы потери информации в @xz массиве. После этого цикла, вы в конечном итоге с помощью одного массива, который выглядит следующим образом:

@col = (7, 2, 3, 3, 2, 8, 6, 7, 2); 

Так, при печати:

print "$col[0]\n"; 

Вы получаете, что нулевой элемент: 7.

Мы можем сохранить структуру данных с помощью reference:

#! /usr/bin/env perl 
# 
    use strict;    # Lets you know when you misspell variable names 
    use warnings;   # Warns of issues (using undefined variables 

    use feature qw(say); 
    use Data::Dumper; 

    my @columns; 
    for my $data (<DATA>) { 
     my @data_list = split /\s+/, $data; 
     push @columns, \@data_list; 
} 

say Dumper \@columns; 

__DATA__ 
7  2  3 
3  2  8 
6  7  2 

Здесь вы видите, я включил Data::Dumper распечатать структуру @columns:

$VAR1 = [ 
      [ 
      '7', 
      '2', 
      '3' 
      ], 
      [ 
      '3', 
      '2', 
      '8' 
      ], 
      [ 
      '6', 
      '7', 
      '2' 
      ] 
     ]; 

Как вы можете видеть, каждая запись в массиве @columns теперь другой массив. Однако при печати $columns[0] ссылка на массив не будет печатать то, что вы хотите. Вместо этого он собирается напечатать ссылку Нулевое массива: 7, 2, 3, а не нулевой элемент каждой ссылки массива: 7, 3, 6.

Для этого нам понадобится подпрограмму, которая будет идти через @columns и распечатать нулевую запись каждого из массивов. Здесь я создаю подпрограмму с именем fetch_index что закачает переданный индекс переданного массива:

#! /usr/bin/env perl 
# 
    use strict;    # Lets you know when you misspell variable names 
    use warnings;   # Warns of issues (using undefined variables 

    use feature qw(say); 
    use Data::Dumper; 

    my @columns; 
    for my $data (<DATA>) { 
     my @data_list = split /\s*/, $data; 
     push @columns, \@data_list; 
} 

say join ", ", fetch_index(0, @columns); 

sub fetch_index { 
    my $entry = shift;  #Entry you want from all arrays 
    my @array = @_; 

    my @values; 

    for my $array_ref (@array) { 
     push @values, ${array_ref}->[$entry]; 
    } 
    return @values; 
} 

__DATA__ 
7  2  3 
3  2  8 
6  7  2 

подпрограмма просто проходит через каждую ссылку на массив я хранится в моем массиве, и принес значение $entry от массив. Я вставляю их в мой массив @values и возвращаю его.

+1

Отличное объяснение того, что пошло не так, и как сделать все правильно. –

+0

Что касается 'split()', '\ s +' (почти?) Всегда лучше, чем '\ s *' https://eval.in/238890 –

+1

@ Сухой27 Darn. Ты прав. Обычно я делаю '/ \ s + /'. –

0

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

perl -nE 'say [split]->[1] ' col_data.txt 

будет петля (-n создает неявный while(){} петлю) через данные в col_data.txt, split тема переменной ($_) создание серии анонимных массивов от каждого а затем напечатать второй элемент или, например, «столбец».

Вы можете использовать autosplit command line option (-a), чтобы разделить каждую строку на массив с именем @F (мнемоника: «F» для «Поле»). В более поздних версиях perl, то -a влечет за собой неявную while петли (-n):

perl -anE 'say $F[1] ' col_data.txt 

бы эквивалент предыдущей команды - печать второго столбца:

выхода:

2 
2 
7 

Существует знаменитый и короткий perl workalike для cut, который является более функциональным вариантом на эту тему, и есть this Perl Monks thread.

+0

'perl -anE 'say $ F [1], если/\ S /'' пропускает пустые строки. –

0

perl -a -F' ' -ne 'print "$F[0]\n";' data.txt

здесь $ F [0] является поле вы можете изменить его, соответственно, вы получите ожидаемый результат