我有一个带有冗余列表的输入,如下所示:
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
我真的被困在这里,非常感谢任何帮助!感谢。
答案 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。