如何根据两列的相似性组织表格?

时间:2013-12-30 17:18:53

标签: perl sorting

下表表示我有一个制表符分隔的文件。

1   2     3   
A   Jack  01
A   Mary  02
A   Jack  03
B   Mary  04
B   Mike  05
B   Mary  06
C   Mike  07
C   Mike  08
C   Jack  09

我想解析这个文本文件并根据第1列和第1列创建多个文本文件。 2.每个文本文件将包含数据(第3列),其中第1列和第2列是相同的。因此,在此示例中,数据将按如下方式组织:

> file1.txt
A   Jack  01
A   Jack  03

> file2.txt
A   Mary  02

> file3.txt
B   Mary  04
B   Mary  06

> file4.txt
B   Mike  05

> file5.txt
C   Mike  07
C   Mike  08

> file6.txt
C   Jack  09

#What would be the best way to tackle this? The only method I can think of is to create a 2-dimensional array and then comparing every row/col pair.

编辑:以下代码似乎有效。还有更好的选择吗?

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

my $file = "/home/user/Desktop/a.txt";
my @array =();
open(FILE, $file) || die "cannot open file";

while(my $line = <FILE>){
    my @row = split("\t", $line);
    my $two = $row[1]."\t".$row[2];
    push(@array, $two);
}

close FILE;

@array = uniq(@array);

my $counter = 0;

foreach my $x (@array){
    #unique tab
    open(SEC, $file) || die "cannot open 2nd time\n";
    while(my $line = <SEC>){
        if($line =~ /($x)/){
        my $output = "txt".$counter.".txt";
        print "hit!\n";
        open(OUT, '>>', $output) || die "cannot write out";
        print OUT $line."\n";
        close OUT;
       }
    }
    $counter++;
 }

 close SEC;
 sub uniq {
     return keys %{{ map { $_ => 1 } @_ }};
 }

我知道如何通过命令行对其进行排序(sort -t:-k1,2 a.txt),但我想知道如何在perl中编写它并写出多个文件。

2 个答案:

答案 0 :(得分:1)

连接两个第一个字段并将它们用作哈希键。每个哈希键指向一个数组,您可以在其中添加所有相关的行:

#!/usr/bin/perl

use strict;
use warnings;

open my $fh, "/home/johan/Desktop/tabdel.txt"
    or die $!;

<$fh>;  # Skip header

my $data = {};
while (my $line = <$fh>) {
    # match the fields
    next unless $line =~ /^(\S+)\s+(\S+)\s+\S+/;

    # append $line to the hash value, key is the concatenated two first fields:
    push @{ $data->{"$1 $2"}->{'lines'} }, "$line";
}

my $file_count = 0;
foreach my $key (sort keys %{$data}) {
    my $qfn = "file".(++$file_count).".txt";
    open(my $fh, '>', $qfn)
        or die $!;

    foreach my $line (@{ $data->{$key}->{'lines'} }) {
        print $fh $line;
    }
}

答案 1 :(得分:1)

也许以下内容会有所帮助:

use strict;
use warnings;

my %hash;
my $n = 1;

while (<>) {
    next if $. == 1;
    my @a = split;

    if ( !exists $hash{ $a[0] }{ $a[1] } ) {
        open $hash{ $a[0] }{ $a[1] }, '>', 'file' . $n++ . '.txt' or die $!;
    }

    print { $hash{ $a[0] }{ $a[1] } } $_;
}

用法:perl script.pl inFile.txt

确认ikegami关于数据集很大的可能用完文件句柄的观点,这里有一个选项,用于收集哈希值的结果,然后将结果打印到文件中(用法与上面的脚本):

use strict;
use warnings;

my ( %hash, %seen );
my $n = 0;

while (<>) {
    next if $. == 1;
    my ( $key, $elem ) = /(.+\s+)(\d+)\Z/;
    push @{ $hash{$key} }, $elem;
}

for my $key ( sort { $hash{$a}->[0] <=> $hash{$b}->[0] } keys %hash ) {
    $n++ if !$seen{$key}++;
    open my $fh, '>', 'file' . $n . '.txt' or die $!;
    print $fh "$key$_\n" for @{ $hash{$key} };
}