【问题标题】:Retrieve unique values from column based on value from other column根据其他列的值从列中检索唯一值
【发布时间】:2015-05-30 14:07:41
【问题描述】:

我有一张这样的桌子

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 中做到这一点?

【问题讨论】:

  • 表格是否按照示例排序?
  • 是的,先根据符号,再根据长度

标签: arrays perl data-structures


【解决方案1】:

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 中)。它还按符号和长度(在%ids_of 中)存储每个ID。它保留了所有数据,因此如果您有大量数据,这可能不是很有效。

【讨论】:

  • 我的表有 36000 行
  • 更多地取决于文件大小 - 它会将大部分文件保留在内存中,并增加开销,因为它就是这样工作的。 10 字节左右的 36000 行无需担心。
【解决方案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();

【讨论】:

    【解决方案3】:

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

    我使用来自(List::Util,这是核心发行版的一部分)中的max 函数来获得每个symbol 的最大length 值,并使用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
    

    输出

    This is your %hash:
    $VAR1 = {
              'A' => {
                       '10' => [
                                 'id_1'
                               ],
                       '15' => [
                                 'id_2',
                                 'id_3'
                               ]
                     },
              'B' => {
                       '25' => [
                                 'id_5'
                               ],
                       '20' => [
                                 'id_4'
                               ]
                     }
            };
    
    A       15      id_2; id_3
    B       25      id_5
    

    【讨论】:

      猜你喜欢
      • 2015-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多