【问题标题】:Matching strings in reverse order in Perl在 Perl 中以相反的顺序匹配字符串
【发布时间】:2015-12-09 19:24:33
【问题描述】:

我有这个文件,第一列中有一对由空格分隔的字符串,另外两列有值。 我想创建一个新文件,其中字符串对在同一行中匹配,无论它们的顺序如何。 例如,打印包含对“GAT_1 GAT_2”的行,以及旁边包含“GAT_2 GAT_1”的行。 将每个字符串分配给给定对的变量后,如何在不重复的情况下比较它们的不同行?

# discard headers

foreach $line (@file) {
  @columns = split (/\t/, $line);
  @strings = split (/\s/, $columns[0]);
    # pseudocode:
foreach line that has pair "$strings[0] $strings[1]" {
    print $line,"\t", and $line where pair is "$strings[1] $strings[0]"

Input:
   pair         val1    val2
GAT_1 GAT_2     0.2     4.5
GAT_1 GAT_3     0.1     0.2
GAT_4 GAT_5     0.9     7.5
GAT_5 GAT_4     0.5     8.3
BLAC BABA       8.3     1.3
BABA BLAC       8.9     1.1
GAT_2 GAT_1     1.2     2.1
GAT_3 GAT_1     3.4     4.3


Ouput:
   pair        val1     val2       pair        val1   val2
GAT_1 GAT_2     0.2     4.5    GAT_2 GAT_1     1.2     2.1
GAT_1 GAT_3     0.1     0.2    GAT_3 GAT_1     3.4     4.3
GAT_4 GAT_5     0.9     7.5    GAT_5 GAT_4     0.5     8.3
BLAC BABA       8.3     1.3    BABA BLAC       8.9     1.1

【问题讨论】:

  • 您只关心匹配(反转)对的行吗?此外,您如何在拆分后强制执行严格数量的值?当然,这是为了什么?
  • 看来您自己并没有很努力地解决这个问题。伪代码是一个开始,但实际的努力呢?
  • @sln 是的,我只关心那些行,但它们都应该有一个匹配的反向对。我试图避免为每个匹配生成具有以下输出的文件:pair val1 val2 pair val1 val2 GAT_1 GAT_2 0.2 4.5 GAT_2 GAT_1 1.2 2.1 GAT_2 GAT_1 1.2 2.1 GAT_1 GAT_2 0.2 4.5 但我不知道如何强制执行严格的数量拆分后的值。这是为了消除文件中的冗余,因为对被视为不同的实体,但它们实际上是相同的。
  • @Matt Jacob 我真的想不出一个算法来解决这个问题,问题应该是“这可能吗?”
  • 这就是编程——一切皆有可能! ;-) 专门研究散列。你的输入文件有多大?

标签: regex perl match


【解决方案1】:

这是解决此问题的一种方法,它适用于任意数量的值列。基本方法是我在comment 中提出的建议,即规范化键,然后将我们找到的任何值推送到数组中。

use strict;
use warnings;

my %unique;

while (<DATA>) {
    chomp;
    next unless /^\S/;
    my @fields = split;

    my $key = join(' ', sort(splice(@fields, 0, 2)));
    push(@{$unique{$key}}, @fields);
}

for my $key (keys(%unique)) {
    print join("\t", $key, @{$unique{$key}});
    print "\n";
}

__DATA__
   pair         val1    val2
GAT_1 GAT_2     0.2     4.5
GAT_1 GAT_3     0.1     0.2
GAT_4 GAT_5     0.9     7.5
GAT_5 GAT_4     0.5     8.3
BLAC BABA       8.3     1.3
BABA BLAC       8.9     1.1
GAT_2 GAT_1     1.2     2.1
GAT_3 GAT_1     3.4     4.3

输出:

GAT_4 GAT_5     0.9     7.5     0.5     8.3
GAT_1 GAT_2     0.2     4.5     1.2     2.1
BABA BLAC       8.3     1.3     8.9     1.1
GAT_1 GAT_3     0.1     0.2     3.4     4.3

【讨论】:

  • 我现在明白你所说的“标准化”是什么意思了。这是我自己无法弄清楚的“拼接”。谢谢。为什么需要“下一个,除非 /^\S/;”?
  • next unless ... 行会跳过具有前导空格的行,从而忽略标题行。您也可以使用next if $. == 1 明确跳过第一行。
  • 感谢您的解释。
【解决方案2】:

https://stackoverflow.com/a/34189380/103780 的一点点变化都会给你你想要的: (未经测试): my @keys = splice(@fields, 0, 2); my $key = join(' ', @keys); my $skey = join (' ', sort @keys); push(@{$unique{$skey}{$key}}, @fields);

for my $skey (keys(%unique)) { for my $key (keys(%unique{$skey})) { print join("\t", $key, @{$unique{$skey}{$key}}); print "\t"; } print "\n"; }

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    相关资源
    最近更新 更多