根据第二个文件中相应的ID列表从文件中提取第一个条目?

时间:2018-03-01 18:00:14

标签: linux perl unix awk

我有一个2文本文件。 file1 包含ID:

0   ABCD  
3   ABDF
4   ACGFR
6   ABCD
7   GFHTRSFS

file2

ID001  AB  ACGFR  DF  FD  GF  TYFJ  ANH  
ID002  DFR  AG  ABDF  HGT  MNJ  POI  YUI
ID003  DGT  JHY  ABCD  YTRE  NHYT  PPOOI  IUYNB
ID004  GFHTRSFS  MJU  UHY  IUJ  POL  KUH  KOOL

如果文件1的第二列与文件2中的任何条目匹配,那么文件2的第一列应该是它的答案。

输出应该是:

0   ID003
3   ID002
4   ID001
6   ID003
7   ID004

(file1(ABCD)的第2列找到与ID003的第3行的第3行匹配。因此,ID003应该是它的答案)。

我也尝试过其他帖子的例子,但不知怎的,它们与此不匹配。

任何帮助都将不胜感激。

亲切的问候

1 个答案:

答案 0 :(得分:1)

当尝试将一个文件中的记录与另一个文件中的记录进行匹配时,我们的想法是使用hash ( also known as an associative array, set of key-value pairs, or dictionaries )来存储第一列与其余列之间的关系。实际上,创建以下关系:

file1: ABCD     -> 0
       ABDF     -> 3
       ACGFR    -> 4
       FGHTRSS  -> 6
       GFHTRSFS -> 7

file2: AB    -> ID001
       ACGFR -> ID001
       DF    -> ID001
       ...
       ANH   -> ID001
       DFR   -> ID002
       AG    -> ID002
       ...
       KUH   -> ID004
       KOOL  -> ID004

文件之间记录的实际匹配等于确定 如果两个哈希值都存在,则file1和file2都为每个file1记录定义了密钥。在这里,我们可以看到ACGFR是两者的关键,因此我们可以匹配4ID001,依此类推其他键。

在perl中,我们可以通过分配值对来创建哈希:

my %hash = ( foo => 1, bar => 2 );

也可以使用引用创建哈希:

my $hash_ref = { foo => 1, bar => 2 };

可以使用keys函数找到密钥,并可以提取单个值:

my $val1 = $hash{ foo };       # regular hash
my $val2 = $hash_ref->{ foo }; # hash reference

可以使用exists函数测试特定键是否为哈希的成员。

有了这个背景,这里有一种方法可以在perl中执行此操作:

<强> matchup_files.pl

#!/usr/bin/env perl

use warnings;
use strict;

my $usage = "usage: $0 file1 file2\n";

my ($file1, $file2) = @ARGV;
for my $file ($file1, $file2) {
    die $usage unless defined $file && -f $file; # -f checks whether $file is an actual file
}

# Create mappings col2 -> col1
#                 col3 -> col1
#                 col4 -> col1
my $h1 = inverted_hash_file_on_first_column( $file1 );
my $h2 = hash_file_on_first_column( $file2 );

# Try to find matching pairs
my $matches = {};
for my $h1_key ( keys %$h1 ) {
    my $h1_val = $h1->{$h1_key};
    if ( exists $h2->{ $h1_val } ) {
        # We have a match!
        my $num = $h1_key;
        my $id  = $h2->{ $h1_val };
        $matches->{ $num } = $id;
    }
}

# Print them out in numerical order
for my $num ( sort { $a <=> $b } keys %$matches ) {
    my $id = $matches->{$num};
    print join("  ", $num, $id) . "\n";
}

exit 0; # Success

sub inverted_hash_file_on_first_column {
    my ($file) = @_;
    return _hash_file($file, 1);
}

sub hash_file_on_first_column {
    my ($file) = @_;
    return _hash_file($file, 0);
}

sub _hash_file {
    my ($file, $inverted) = @_;

    my $fhash = {};
    open my $fh, "<", $file or die "Unable to open $file : $!";
    while ( my $line = <$fh> ) {
        my @fields = split /\s+/, $line; # Split line on whitespace
        my $key = shift @fields; # First column
        for my $field ( @fields ) {
            if ( $inverted ) {
                die "Duplicated field '$field'" if exists $fhash->{ $key };                
                $fhash->{ $key } = $field;
            } else {
                die "Duplicated field '$field'" if exists $fhash->{ $field };
                $fhash->{ $field } = $key;
            }
        }
    }
    return $fhash;
}

<强>输出

matchup_files.pl input1 input2
0  ID003
3  ID002
4  ID001
6  ID003
7  ID004