Arrays 对HoHoA值进行排序和比较

Arrays 对HoHoA值进行排序和比较,arrays,perl,sorting,hash,Arrays,Perl,Sorting,Hash,我的HoHoA设置如下: #!/usr/bin/perl use warnings; use strict; my %experiment = ( 'gene1' => { 'condition2' => ['XLOC_000347','80', '0.5'], 'condition3' => ['XLOC_000100', '50', '0.2']

我的HoHoA设置如下:

#!/usr/bin/perl
use warnings;
use strict;

my %experiment = (
    'gene1' =>  {
                       'condition2' => ['XLOC_000347','80', '0.5'],
                       'condition3' => ['XLOC_000100', '50', '0.2']
                   },
    'gene2'   =>  {
                       'condition1' => ['XLOC_025437', '100', '0.018'],
                       'condition2' => ['XLOC_000322', '77', '0.22'],
                       'condition3' => ['XLOC_001000', '43', '0.02']
                   },
    'gene3'   =>  {
                      'condition1' => ['XLOC_025437', '100', '0.018'],
                      'condition3' => ['XLOC_001045', '23', '0.0001']
                   },
    'gene4'   =>  {
                      'condition3' => ['XLOC_091345', '93', '0.005']
                   }

);
我试图找到所有在至少两种情况下重叠的“基因”,并为每个基因打印出具有最低值(例如q_值)的情况。然后我想按这个值排序。以下是我目前的代码:

循环第1个关键点,以查找第2个关键点中至少2个出现的所有关键点

my(%overlap, %condition_name);
my ($xloc, $q_val, $percentage, %seen);

for my $gene (sort keys %experiment) { 
    for my $condition (sort keys %{$experiment{$gene}}) {
        $condition_name{$condition} = 1;
        $seen{$gene}++; # Counts for each occurrence of gene 
        $overlap{$gene} = 1 if $seen{$gene} > 1;
    }
}
对于每个重叠实例,打印出找到key1的每个条件(key2)以及相关值:

my @cond_name = keys %condition_name;
foreach my $gene (keys %overlap){ 
        foreach my $condition (@cond_name){
            next unless exists $experiment{$gene}{$condition};
            ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
            print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";
        }
        print "\n";
}
产出:

condition3  gene3   XLOC_001045 0.0001  23
condition1  gene3   XLOC_025437 0.018   100

condition3  gene1   XLOC_000100 0.2 50
condition2  gene1   XLOC_000347 0.5 80

condition3  gene2   XLOC_001000 0.02    43
condition1  gene2   XLOC_025437 0.018   100
condition2  gene2   XLOC_000322 0.22    77
我尝试用两种方式更改输出:

  • 对于key1的每个重叠实例,根据第二个关键点的一个值比较它们。例如,对于
    gene1
    ,我想比较
    condition3
    condition2
    (q_值)的第一个值,只保留最低的值
期望输出:

condition3  gene3   XLOC_001045 0.0001  23    
condition3  gene1   XLOC_000100 0.2 50
condition1  gene2   XLOC_025437 0.018   100
  • 其次,我想按照我选择的相同值(q_值)对其进行排序,以给出:
所需最终输出(见下文更新):

更新:16.9.13

我已经开始悬赏这个问题,因为答案(虽然很好)并没有达到我所希望的。如果需要澄清问题,请让我知道

我的最终期望输出也有轻微变化: 如上所述,我想比较其中一个值上的每个条件,并根据该值对基因进行排序。理想情况下,我希望为每个已排序的基因输出每个条件(并在内部按相同的值排序):

condition3  gene3   XLOC_001045 0.0001  23 # Lowest q_value
condition1  gene3   XLOC_025437 0.018   100 # Other condition(s) for the gene with lowest q_value...

condition1  gene2   XLOC_025437 0.018   100 # For each gene, rank by q_value
condition3  gene2   XLOC_001000 0.02    43
condition2  gene2   XLOC_000322 0.22    77

condition3  gene1   XLOC_000100 0.2 50
condition2  gene1   XLOC_000347 0.5 80

构建另一个HoH,而不是打印。在最后反复讨论,决定打印什么

因此,在顶部添加以下内容:

my %lowest;
my $sortkey='q_val';
在中间,进行以下编辑:

foreach my $condition (@cond_name){
    next unless exists $experiment{$gene}{$condition};
    ## ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
    ## print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";

    my %cond;
    @cond{ qw( xloc percentage q_val ) } = @{$experiment{$gene}{$condition}};
    # >= may also be appropriate
    if (!defined($lowest{$gene}) or $lowest{$gene}{$sortkey} > $cond{$sortkey}) {  
        @cond{ qw( condition gene ) } = ($condition, $gene); # useful at print time
        $lowest{$gene} = \%cond
    }
}
## print "\n";
最后:

# NB: <=> is for numeric comparison. Use cmp for non-numeric keys.
for my $gene (sort { $lowest{$a}{$sortkey} <=> $lowest{$b}{$sortkey} } keys %lowest) {
    local ($, , $\)=("\t","\n");
    print @{$lowest{$gene}}{qw( condition gene xloc q_val percentage )};
}
#NB:用于数字比较。对非数字键使用cmp。
对于我的$gene(排序{$lowest{$a}{$sortkey}$lowest{$b}{$sortkey}}}键%lowest){
本地($,$\)=(“\t”,“\n”);
打印{$最低{$基因}{qw(条件基因xloc q_val百分比)};
}

您的代码太复杂了。要获得具有两种或两种以上条件的基因列表,请使用grep:

my @genes = grep { keys %{$experiment{$_}} >= 2 } keys %experiment;
接下来,我们需要根据最小q_值对基因进行排序。最简单的方法(尽管目前不是最有效的方法)是首先找到每个基因的最小值,并将其填入哈希:

use List::Util qw(min);

my %minimum;
foreach my $gene (@genes) {
    my @q_vals;
    push @q_vals, $experiment{$gene}{$_}[2] for keys %{$experiment{$gene}};
    $minimum{$gene} = min @q_vals;
}
当我们得到所有最小值后,我们可以对它们进行排序:

@genes = sort { $minimum{$a} <=> $minimum{$b} } keys %minimum;

这不是一个非常有效的方法,因为我们要多次遍历散列。您可能需要考虑将数据结构更改为更易于管理的东西。

< P>我已经测试过这个代码,这是我尽可能简化的。我从您发布的原始代码开始,希望我没有错过任何最初的更改。注释内联:

#!/usr/bin/perl
use warnings;
use strict;

my %experiment = (
    'gene1' =>  {
                       'condition2' => ['XLOC_000347','80', '0.5'],
                       'condition3' => ['XLOC_000100', '50', '0.2']
                   },
    'gene2'   =>  {
                       'condition1' => ['XLOC_025437', '100', '0.018'],
                       'condition2' => ['XLOC_000322', '77', '0.22'],
                       'condition3' => ['XLOC_001000', '43', '0.02']
                   },
    'gene3'   =>  {
                      'condition1' => ['XLOC_025437', '100', '0.018'],
                      'condition3' => ['XLOC_001045', '23', '0.0001']
                   },
    'gene4'   =>  {
                      'condition3' => ['XLOC_091345', '93', '0.005']
                   }

);
我将您的一些
我的
声明移动到了需要它们的地方。我还创建了
qvals
散列,我使用它来代替您的
overlap
散列。它将包含每个基因的最小qval,以便于分类

my (%qvals, %seen);

for my $gene (sort keys %experiment) { 
    for my $condition (sort keys %{$experiment{$gene}}) {
        $seen{$gene}++; # Counts for each occurrence of gene 
所以现在我们需要构建qvals散列。这将是打印输出的第一个(外部)排序键。对于每个基因的第一个条件,我们将保存该基因的Q值。对于后续的条件,如果我们找到一个较小的Q值,我们将保存该值

        if ((not exists $qvals{$gene}) || # First time we've seen this gene, OR
            ($qvals{$gene} > $experiment{$gene}{$condition}[2])) { # Has a smaller q value
            $qvals{$gene} = $experiment{$gene}{$condition}[2];
        }
    }
}
您可能不熟悉这种排序语法。大括号
{}
中的东西是一个“排序块”。通过在google或您的Linux控制台中键入
perldoc sort
,您可以学到比我所能解释的多得多的东西-它允许您做非常复杂的事情,但在这里,我们所使用的只是对我们正在排序的数据以外的其他数据进行排序。在这里,我们将基因(
键%qvals
)按其最小qvalue
$qvals{$a}
进行排序
$a
$b
排序
自动使用,不必担心声明它们,
是太空船操作符-它就像超级比较,如果操作数相等,返回
0
;如果左操作符较小,返回
-1
,如果左操作符较大,返回
+1
。基本上,如果不指定排序块,默认情况下,排序将使用
{$a$b}

foreach my $gene (sort {$qvals{$a} <=> $qvals{$b}} keys %qvals) { # Sort the genes on ascending minimum q-val 
    if ($seen{$gene} == 1) {next;} # Skip gene if it only has one condition
    foreach my $condition (sort # Sort conditions on ascending q-val
我得到以下输出:

condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100

condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77

condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80


这太棒了,谢谢。我需要准确地理解这里发生的事情,但这看起来是一个很好的解决方案
@cond{qw(…)}=…
将数组转换为哈希。这不是必需的:可以说
$sortkey=2
并按数组索引排序。但是,构建一个结果集供以后显示是一个常见的习惯用法,并且创建/使用的时间通常相差很远。将名称附加到字段是很好的
@cond{qw(condition-gene)}=…
将标识字段附加到哈希允许您稍后重新构造结果,而不必挖掘父键名称。存储空间是不使用散列的一个原因。如果您的结果集很大,则哈希占用的列表空间大于2倍(无论如何,在本例中)。
$,
是打印列表时显示的字段分隔符
$\
是记录分隔符。local()约束对该块的赋值;它们将恢复为块外的先前值。它与
print join(“\t”,@{…}{…}),“\n”
相同。这实际上并不像我想的那样有效。我得到的输出不一定对应于每个基因q值最低的条件……你能举个例子吗?我的测试程序的输出与您的最终输出一致-太好了-谢谢!这看起来是一个非常优雅的解决方案。然而,我只想按q_值排序,而不是按基因名称排序-我如何对此进行修改?@FlyingFrog从外部
foreach
循环中删除
sort
。这就是我尝试的。然而,尽管内部条件被正确排序,但基因并不是按q_值进行全局排序的。将你的输出与我的期望输出进行比较,看看我的意思…@FlyingFrog他们也没有在你期望的输出中进行全局排序:最后四个q_值
        if ((not exists $qvals{$gene}) || # First time we've seen this gene, OR
            ($qvals{$gene} > $experiment{$gene}{$condition}[2])) { # Has a smaller q value
            $qvals{$gene} = $experiment{$gene}{$condition}[2];
        }
    }
}
foreach my $gene (sort {$qvals{$a} <=> $qvals{$b}} keys %qvals) { # Sort the genes on ascending minimum q-val 
    if ($seen{$gene} == 1) {next;} # Skip gene if it only has one condition
    foreach my $condition (sort # Sort conditions on ascending q-val
                {$experiment{$gene}{$a}[2] <=> $experiment{$gene}{$b}[2]}
                keys $experiment{$gene} ) { 
        next unless exists $experiment{$gene}{$condition};
        my ($xloc, $percentage, $q_val) = @{$experiment{$gene}{$condition}};
        print "$condition\t$gene\t$xloc\t$q_val\t$percentage\n";
    }
    print "\n";
}
condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100

condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77

condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80
use 5.10.0;
$, = "\t";
do {
    my ( $gene, @conds ) = @$_;
    say( ( $gene, @$_ )[ 1, 0, 2, 4, 3 ] ) for @conds;
    say "";
    }
    for (
    sort { $a->[1][3] <=> $b->[1][3] }
    map {
        my $conds = $experiment{$_};
        [   $_ => sort { $a->[3] <=> $b->[3] }
                map { [ $_, @{ $conds->{$_} } ] }
                keys %$conds
        ]
    } grep { keys %{ $experiment{$_} } > 1 } keys %experiment
    );
condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100

condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77

condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80
use 5.10.0;
$, = "\t";
say @$_[ 1, 0, 2, 4, 3 ]
    for (
    map {
        my ( $gene, @conds ) = @$_;
        map { [ $gene, @$_ ] } @conds
    }
    sort { $a->[1][3] <=> $b->[1][3] }
    map {
        my $conds = $experiment{$_};
        [   $_ => sort { $a->[3] <=> $b->[3] }
                map { [ $_, @{ $conds->{$_} } ] }
                keys %$conds
        ]
    } grep { keys %{ $experiment{$_} } > 1 } keys %experiment
    );
condition3      gene3   XLOC_001045     0.0001  23
condition1      gene3   XLOC_025437     0.018   100
condition1      gene2   XLOC_025437     0.018   100
condition3      gene2   XLOC_001000     0.02    43
condition2      gene2   XLOC_000322     0.22    77
condition3      gene1   XLOC_000100     0.2     50
condition2      gene1   XLOC_000347     0.5     80