从冗余列表创建矩阵

时间:2017-04-06 12:22:53

标签: list perl matrix

我有一个带有冗余列表的输入,如下所示:

Sample1.14  Water
Sample2.45  Air
Sample1.16  Dirt
Sample1.14  Water
Sample2.45  Air
Sample1.16  Dirt
Sample1.14  Water
Sample2.45  Air
Sample1.16  Dirt
Sample1.16  Dirt
Sample1.14  Dirt
Sample2.45  Air
Sample1.16  Air

我创建了一个哈希值,用于计算每个样本给出结果Water,Air,Dirt的频率(注意这只是示例数据,但结构相同)。

    use warnings;
    use strict;
    my $inPut = "ExampleSample";
    open(READ,$inPut) || die "Coult not read $inPut: $!";

    my %sampleHash;

    while (<READ>) {

        chomp;
        my @temp = split("\t",$_);

        my $sample = $temp[0];

        my $type = $temp[1];

        $sampleHash{$type}{$sample} += 1;

    }

这按预期工作,并作为输出:

$VAR1 = {
          'Dirt' => {
                      'Sample1.16' => 4,
                      'Sample1.14' => 1
                    },
          'Air' => {
                     'Sample1.16' => 1,
                     'Sample2.45' => 4
                   },
          'Water' => {
                       'Sample1.14' => 3
                     }
        };

由于这是一个安静的数据结构,因此我想把这些数据放到一个矩阵中,我有点迷失了。

Desired Output或此示例的转置并不重要:

    Sample1.14  Sample2.45  Sample1.16
Air     0           4           1
Dirt    4           0           4
Water   3           0           0

我真的被困在这里,非常感谢任何帮助!感谢。

2 个答案:

答案 0 :(得分:2)

你可以将哈希哈希“混乱”到一个数组数组中,然后将其输入Acme::Tools :: pivot()或Data::Pivot :: pivot()。像这样:

use Acme::Tools;
my $data={
    'Dirt' => {
        'Sample1.16' => 4,
        'Sample1.14' => 1
    },
    'Air' => {
        'Sample1.16' => 1,
        'Sample2.45' => 4
    },
    'Water' => {
        'Sample1.14' => 3
    }
};
my @sample=uniq(sort map keys(%$_), values %$data);
my @element=sort keys %$data;
my $data2=[ map { my $x=$_; map [$x,$_,$$data{$x}{$_}||' 0'], @sample } @element ];
print tablestring([Acme::Tools::pivot($data2,"Element")]);

输出:

Element Sample1.14 Sample1.16 Sample2.45
------- ---------- ---------- ---------- 
Air              0          1          4
Dirt             1          4          0
Water            3          0          0

答案 1 :(得分:1)

在Perl中创建唯一列表的最简单方法是将元素用作具有虚拟值的哈希键。填充哈希后,您可以使用keys获取唯一的值列表。

my %samples;
$samples{"some value"} = 1;
$samples{"some other value"} = 1;
$samples{"some value"} = 1;
my @samples = sort keys %samples;

如果要使Perl的行为类似awk,则可以将split函数与单个空格参数一起使用。如果要将拆分结果分配给两个变量,可以使用Perl的列表表示法。

my ($a, $b) = split ' ';

复杂的部分是构建表。这可以通过for循环或map来完成。 for循环的使用可能更容易阅读,但map允许更紧凑的表示法。

以下内容创建一个数组引用(方括号),并使用map表达式的返回列表填充数组,前缀为$t值。 map表达式需要一堆代码和一个列表,并为列表的每个元素执行代码。变量$_中提供了当前列表元素的值。

[ $t, map { $sampleHash{$t}{$_} or '0' } @samples ]

如果您嵌套map个表达式,则必须为外部$_提供一个名称,以便从内部map访问它,因为内部$_会影响外部#! /usr/bin/perl use strict; use warnings; my %sampleHash; my %samples; my %types; while (<DATA>) { chomp; my ($sample, $type) = split ' '; $sampleHash{$type}{$sample} += 1; $samples{$sample} = 1; $types{$type} = 1; } my @samples = sort keys %samples; my @types = sort keys %types; my @table = (['', @samples], map { my $t=$_; [ $t, map { $sampleHash{$t}{$_} or '0' } @samples ] } @types ); my $row; format = @<<<<<< @|||||||||| @|||||||||| @|||||||||| @$row . for $row (@table) { write; } __DATA__ Sample1.14 Water Sample2.45 Air Sample1.16 Dirt Sample1.14 Water Sample2.45 Air Sample1.16 Dirt Sample1.14 Water Sample2.45 Air Sample1.16 Dirt Sample1.16 Dirt Sample1.14 Dirt Sample2.45 Air Sample1.16 Air

在Perl中格式化表格的基本方法是使用Perl的报表功能perlform。为此,您必须定义交替行的列表:首先是模式行,然后是值行。

如果你把所有的东西放在一起你的例子就变成了这个

open

输出此

         Sample1.14   Sample1.16   Sample2.45
Air           0            1            4
Dirt          1            4            0
Water         3            0            0

注意:您想要的输出与您的输入不符。

要阅读文件,您必须使用__DATA__保留代码。我仅使用{{1}}部分来简化示例,以获得MCVE