根据其他列的值从列中检索唯一值

时间:2015-03-26 14:02:58

标签: arrays perl data-structures

我有一张这样的表

symbol    length    id
A         10        id_1
A         15        id_2
A         15        id_3
B         20        id_4
B         25        id_5
...       ...       ...

我想在新表中打印以下内容

symbol    length    id
A         15        id_2; id_3
B         25        id_5
...       ...       ...

所以我想遍历symbol列。当此列中存在重复值时,我想打印数字长度值最大的行(例如:符号B)。当最大length值相等时,我想合并id列中的值(例如:符号A)并打印此新行。

我应该如何在perl中执行此操作?

3 个答案:

答案 0 :(得分:2)

perl中用于合并重复项的工具是一个哈希。散列是键值对,但有用的部分是 - 值可以是数组(引用)。

我建议这样的事情:

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

my %length_of;
my %ids_of;

my $heading_row = <DATA>;
while (<DATA>) {
    my ( $symbol, $length, $id ) = split;
    if ( not defined $length_of{$symbol} or $length_of{$symbol} < $length ) {
        $length_of{$symbol} = $length;
    }
    push( @{ $ids_of{$symbol}{$length} }, $id );
}

print join( "\t", "symbol", "length", "ids" ), "\n";
foreach my $symbol ( sort keys %ids_of ) {
    my $length = $length_of{$symbol};
    print join( "\t",
        $symbol, 
        $length,
        join( "; ", @{ $ids_of{$symbol}{$length} } ) ),
        "\n";
}

__DATA__
symbol    length    id
A         10        id_1
A         15        id_2
A         15        id_3
B         20        id_4
B         25        id_5

这是做什么的 - 迭代您的数据,并保存最高length值(在%length_of中)。它还存储每个ID - 按符号和长度(在%ids_of中)。它保留了所有这些,所以如果您拥有大量数据,这可能效率不高。

答案 1 :(得分:2)

记住最后一个符号和长度并累积id:

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

my ($last_l, $last_s, @i);

sub out {
    print "$last_s\t$last_l\t", join(";", @i), "\n"
}

while (<>) {
    my ($s, $l, $i) = split;
    out() if $last_s and $s ne $last_s;
    undef @i if $last_l < $l;
    push @i, $i;
    $last_s = $s;
    $last_l = $l;
}
out();

答案 2 :(得分:0)

此方法通过使用symbollength列中的值作为键并将id列中的值添加为数组引用来构建hash of hashes of arrays。对于您提供的简单数据集,实际上并不需要这样复杂的数据结构,但在未对数据进行排序的情况下,下面显示的方法可能更灵活。

我使用List::Util中的max函数(它是核心发行版的一部分)来获取每个length的最大symbol值,以及{{1帮助可视化事物。

Data::Dumper

<强>输出

use Data::Dumper ;
use List::Util 'max';
use v5.16; 

my (%hash, @lines) ;

while ( <DATA>) {
    chomp ;
    next if $. == 1 ;
    push @lines,  [ split ] ;
}

for (@lines) { 
    push @{ $hash{ $_->[0] }{ $_->[1] } }, $_->[2] ;
}

say "This is your %hash:\n", Dumper \%hash; 

for my $symbol ( keys %hash ) {
    my $max =  max ( keys $hash{$symbol} ) ;
    say "$symbol \t",  "$max \t",  join "; ", @{ $hash{$symbol}{$max} };
}

__DATA__
symbol    length    id
A         10        id_1
A         15        id_2
A         15        id_3
B         20        id_4
B         25        id_5