Транспонировать в perl

Я начал изучать perl и хотел попробовать новые вещи.

У меня есть некоторые проблемы при обработке текста. У меня есть текст формы,

0 1 2 3 4 5 6 7 8 9 10

6 7 3 6 9 3 1 5 2 4 6

Я хочу перенести этот текст. Например, я хочу сделать строки как столбцы и столбцы как строки. Id есть способ сделать это в perl?

Спасибо всем.

Ответ 1

Итак, это решение использует массив массивов, каждый вложенный массив представляет собой строку данных. Очень просто вы перебираете столбцы в каждом строки и нажимать их на другой массив массивов, используя столбец index как индекс, который должен нажимать значение. Это имеет значение поворота данных по вашему запросу.

#!/usr/bin/env perl

my @rows = ();
my @transposed = ();

# This is each row in your table
push(@rows, [qw(0 1 2 3 4 5 6 7 8 9 10)]);
push(@rows, [qw(6 7 3 6 9 3 1 5 2 4 6)]);

for my $row (@rows) {
  for my $column (0 .. $#{$row}) {
    push(@{$transposed[$column]}, $row->[$column]);
  }
}

for my $new_row (@transposed) {
  for my $new_col (@{$new_row}) {
      print $new_col, " ";
  }
  print "\n";
}

Это приводит к:

0 6 
1 7 
2 3 
3 6 
4 9 
5 3 
6 1 
7 5 
8 2 
9 4 
10 6

Ответ 2

Вот схема одного из способов переноса данных. Работа через этот пример будет поучительной, потому что вам нужно будет использовать CPAN, вы узнаете о полезном List::Util и List::MoreUtils, вы узнаете основы сложных структур данных (см. perlreftut, perldsc и perllol), и вы получите использовать итератор в Perl.

use strict;
use warnings;
use List::MoreUtils qw(each_arrayref);

my @raw_data = (
    '0 1 2 3 4 5 6 7 8 9 10',
    '6 7 3 6 9 3 1 5 2 4 6',
);

my @rows = ... ; # Look up map() and split() to fill in the rest.
                 # You want an array of arrays.

my @transposed;  # You will build this in the loop below.

my $iter = each_arrayref(@rows);  # See List::MoreUtils documentation.

while ( my @tuple = $iter->() ){
    # Do stuff here to build up @transposed, which
    # will also be an array of arrays.
}

Ответ 3

Конечно, есть, и Майк указал на самый простой способ. Если вы учитесь, вы, вероятно, захотите написать свою собственную функцию?
Во-первых, вы хотите split каждую строку в пробелах, чтобы получить массив значений (или push список слов в массив, как в Dalton answer, в Perl всегда есть более чем один способ сделать что-либо)
Затем для каждого элемента массива, вы хотите напечатать его и его коллегу во втором массиве на одной строке. (Что вы будете делать, если один массив закончится перед другим?)

Конечно, если вы хотите изучать Perl, вы также обязательно захотите научиться использовать CPAN, так что по-прежнему стоит попробовать использовать Data:: Pivot.

Ответ 4

Здесь мой новый script для переноса файла с разделителями табуляции. Измените \t на свой разделитель, если хотите.

#!/usr/bin/perl -anF/\t|\n/
$n = @F - 1 if !$n;
for $i (0..$n) {
    push @{ $m->[$i] }, $F[$i];
}
END {
    for $r (@$m) {
        print join("\t", @$r), "\n";
    }
}

или как 104 символа "один лайнер" (с добавлением апострофа-обратной косой черты-новой строки-апострофы, чтобы избежать горизонтальной прокрутки):

perl -anF'\t|\n' -e'[email protected]!$n;for(0..$n){[email protected]{$$m[$_]},$F[$_]}'\
'END{print map{join"\t",@$_,"\n"}@$m}'

Ответ 5

use strict;
# read the first line
my @labels = split ' ', <>;
# read and ignore the empty second line
<>;
# read the third line
my @values = split ' ', <>;
# transpose (I suppose you'll do more with the table than just printing it)
my %table = map { $labels[$_] => $values[$_] } 0..$#labels;
# print
foreach (@labels) {
    print "$_ $table{$_}\n";
}

Ответ 8

use strict;
my ($i, $rows, $cols) = (0, 10, 100);
# initiate array 10x100
my $array = [map {[map {$i++} (1..$cols)]} (1..$rows)];
# transpose array into 100x10 array
my $transpose = [map {[map {shift @$_} @$array]} @{$array->[0]}];

массив должен быть матрицей, то есть столбцы должны быть равны для каждой строки, исходный массив будет уничтожен

этот код не будет использовать дополнительную память для транспонирования, x2 для других библиотек, для большого массива, например, 100x1M, важно