2017-04-06 112 views
1

创建矩阵我有一个多余的列表,它看起来像这样的输入:从冗余列表

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 

我创建可计算每个样品多久给出结果水散,空气,灰尘(注意,这是只是示例数据,但结构相同)。

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 
        } 
     }; 

由于这是安静的进一步下行的东西,我想坏的数据结构,把这个数据成我有些失落矩阵在。

所需的输出或换位这个例子中,没有真正的问题:

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

我真的坚持在这里,任何帮助将非常感谢!谢谢。

+1

你的例子有错误的变量名称。 – simbabque

+0

为了提供帮助,我们需要了解您的下游需求。如果您不知道,请告诉我们您以后打算如何处理数据。你现在的结构非常典型。看数据我会做同样的事情。按类型分组,然后对样本进行计数。这对应于您显示的表格,只要第一个键是行,第二个键是列。 – simbabque

+0

谢谢你的抬头。下游我想创建一个带有矩阵结构的输出文件,以便查看哪个样本最常出现哪种类型,但由于分组是冗余的,我不太确定如何将数据转换为更易读的格式。 – chrys

回答

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,你可以使用分割功能用一个空格的说法。如果你想将分割的结果分配给两个变量,你可以使用Perl的列表表示法。

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

复杂的部分是建立表。这可以使用for循环或map来完成。使用for循环可能更易于阅读,但map允许使用更简洁的记法。

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

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

如果你巢map表达式,你必须给外$_一个名字从内map访问它,因为内$_阴影外。

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

如果你把所有在一起的例子成为该

#! /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 

其输出该

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

注:所需输出不匹配您的输入。

为了阅读文件,你必须保持你的代码使用open。我已经使用__DATA__部分来简化示例以获得MCVE

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