如何从多个分号分隔的列中过滤数据

如何从多个分号分隔的列中过滤数据

我有一个制表符分隔的文件,包含 3 列,其中包含分号分隔的数据。我想过滤每列中的值(满足 3 列中的所有 3 个条件):第一列 (<-0.5)、第二列 (>1)、第三列 (>2)。真实数据有多个列。

输入

-0.6;0.14;-0.56;0.2    10.4;NA;5.1;2    3;1;4;3    A;B;C;D
-0.9;-0.16;-1.1        2.4;0.1;0.9      10;1;3     E;F;G 

所需输出

-0.6;-0.56         10.4;5.1       3;4    A;C
-0.9               2.4            10     E

对于每一行,每列中的值的数量在过滤之前和之后应该相同。

答案1

这是 Perl 的一些疯狂的地方

perl -lane '
    BEGIN {
        @criteria = (
            sub {shift() < -0.5},
            sub {shift() > 1},
            sub {shift() > 2},
        )
    }
    @filtered = ();
    for $i (0..$#F) {
        push @filtered, join ";", grep {$criteria[$i]->($_)} split /;/, $F[$i];
    }
    print join " ", @filtered;
' file | column -t
-0.6;-0.56  10.4;5.1  3;4
-0.9        2.4       10

这更准确地反映了您的要求

perl -lane '
    sub criteria {
        $_[0] < -0.5 and
        $_[1] > 1    and
        $_[2] > 2
    }

    @data = map {[split /;/]} @F;
    @filtered = map {[]} @F;

    for ($i = 0; $i < @{$data[0]}; $i++) {
        @tuple = map {$data[$_][$i]} (0..$#F);
        if (criteria(@tuple)) {
            push @{$filtered[$_]}, $tuple[$_] for (0..$#F);
        }
    }
    print join " ", map {join ";", @$_} @filtered;
' file

答案2

通过awk

  • 测试前三个字段是否满足所有集合成员的条件。 (拆分字段;并测试每一对)

  • 如果是这样,请记住该集合在每个字段中的位置。 (在数组中sel

  • 在第二个块中,遍历所有字段并仅保留与之前的位置匹配的值。

  • 如果找到任何匹配项,则仅打印。

    BEGIN {FS=OFS="\t"}
    {
    #select IDs of value sets to be keept
      split($1,a,";")
      split($2,b,";")
      split($3,c,";")
      nsel=0 ; delete sel
      for ( i in a ) {
          if (a[i]+0<-0.5 && b[i]+0>1 && c[i]+0>2) {
          sel[++nsel]=i
          }
      }
    #if any: run through all fields and reselect
      if (nsel) {
          for (i=1 ; i<=NF ; i++) {
              split($i,a,";")
              $i=a[sel[1]]
              for (j=2 ; j<=nsel ; j++) {
                  $i=$i";"a[sel[j]]
              }
          }
      }
    }
    #print only if any matching set was found
    nsel
    

相关内容