如何使用 Perl 按行和列组织数据?

How can I organize data in rows and columns with Perl?

基本问题是我有很多具有规范化名称的数据点,这些数据点只是从服务器转储到一个文件中,但我需要根据它们的数据自动将这些数据点组织到一个具有行和列的文件中包含(以其规范化名称表示)。


包含所有数据点的原始文件如下(这些不是原始数据点标签,而是简化的标签):

temp_r301
airflow_r301
temp_r345
airflow_r345
solar_w
solar_e
...

如您所见,它们都是一列,因此每行一个标签。

我想组织它们,以便对于每个状态(温度中的“temp”),我在同一行中有相应的信息,例如:

temp_r301 301 airflow_r301 solar_w solar_e     #airflow in 301 and general solar radiation affect temperature (state) in room 301
temp_r345 345 airflow_r345 solar_w solar_e     #airflow in 345 and general solar radiation affect temperature (state) in room 345

当然数组的长度可以变化,所以我们的想法是制作一个算法来检测长度并相应地组织数据。另外,我知道我将不得不使用正则表达式来查找匹配项并定义哪些数据点是状态,哪些数据点是输入,以及知道它们所属的房间。


到目前为止我已经尝试了以下方法:

use strict;
use warnings;
use diagnostics;

my @transpose = ();
my @sorted = ();

push(@sorted, [qw(temp_r301 temp_r345)]);
push(@sorted, [qw(301 345)]);
push(@sorted, [qw(airflow_r301 airflow_r345 solar_w solar_e)]);

for my $sorted (@sorted) {
  for my $column (0 .. $#sorted) {
    push(@{$transpose[$column]}, $sorted->[$column]);
  }
}

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

但这只有在所有数组都具有相同长度的情况下才能正常工作(不是这种情况)。

我还发现了一个可用于将数据存储为矩阵形式(数组的数组)的循环,但是,我似乎仍然找不到将来自不同数组的数据写入矩阵的解决方案:

use strict;
use warnings;
use diagnostics;
use feature 'say';

my @states = qw(temp_r301 temp_r345);
my @zones = qw(301 345);
my @inputs = qw(airflow_r301 airflow_r345 solar_w solar_e);

my @matrix = ();

for my $x (0 .. $#states) {
    for my $y (0 .. $#inputs) {
        $matrix[$x][$y] = $states[$x];           #of course this only copies the states array and
    }                                            #repeats it for each created array
}

for my $aref (@matrix) {                         #print array of arrays
    say "[ @$aref ],";
}

那么,知道我已将所有数据转储到输入文件中,将这些数据排序到矩阵中的最佳方法是什么?有什么循环我应该多加注意吗?我应该使用数组吗?

此问题的详细信息仍不清楚,但解释确实有所帮助。所以这就是我的假设。

我取数据每行一条信息。有些包含标签(描述),后跟房间号,我假设格式为 tag_rN,标识标签适用的房间号。

对于没有房间号的其他人,需要进行额外处理以确定该信息所属的位置。这个问题只提出了一个适用于所有房间的标签示例,与影响它们的太阳辐射有关(见评论),所以这就是所有处理的内容。

一些数据没有按照房间整齐地分类的事实是解析数据的组织方式 non-trivial。由于没有给出详细信息,我只是将其分成两个哈希值,一个按房间号,另一个结构将取决于具体情况。

use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd);

my $file = shift // die "Usage: [=10=] file\n";
open my $fh, '<', $file or die "Can't open $file: $!";

my (%room, %other);
while (<$fh>) { 
    chomp;
    if ( my ($tag, $room_num) = /([^_]+)_r([0-9]+)/ ) {
        $room{$room_num}{$tag} = $_;                  # have room number
    }
    else {                                            # more processing needed
        my ($tag, $value) = parse_line($_);
        push @{ $other{$tag} }, $value;
    }
}
dd \%room; dd \%other; say '';

# Print in CSV format. Header first
my @tags = ( keys %{ $room{ (keys %room)[0] } }, keys %other );
say join ',', 'room', @tags;
foreach my $rnum (keys %room) { 
    say join ',', 
        $rnum, map { $room{$rnum}{$_} // join ' ', @{$other{$_}}  } @tags;
}

sub parse_line {
    my ($line) = @_;
    my ($tag, $value);

    if ($line =~ /solar_w|solar_e/) {   # example from sample data
        $tag   = 'solar';
        $value = $line;
    }
    else { }  # other possibilities

    return $tag, $value;
}

房间号数据以标识描述(“tag”)为key,行为value排序。每个这样的 key-value 对都在分配给每个房间号的 hashref 中。

没有房间号的数据在一个单独的子文件中解析,由于没有给出详细信息,只有一些令牌代码。然后将其存储在另一个哈希中,以便于操作(因为它不依赖于任何一个房间)。

如何从数据中提取标签有点随意,因为它没有在问题中指定。

所有这些都合并成 CSV 格式。以上,加上问题的输入文件和注释中的解释,即来自西面和东面的太阳辐射影响所有房间,打印:

{
  301 => { airflow => "airflow_r301", temp => "temp_r301" },
  345 => { airflow => "airflow_r345", temp => "temp_r345" },
}
{ solar => ["solar_w", "solar_e"] }

room,airflow,temp,solar
345,airflow_r345,temp_r345,solar_w solar_e
301,airflow_r301,temp_r301,solar_w solar_e

注释掉带有 dd ... 的行(来自 Data::Dump)以删除初始诊断打印。然后最后几行是将进入某些文件等的 CSV

有些房间可能缺少一些数据,还有更多的数据可能分类不那么统一。然后那些 headers 的字段将根据需要在某些行中愉快地为空。