查找文件的每一行中至少存在一个值的最小值集

查找文件的每一行中至少存在一个值的最小值集

我有一个像这样的文件df

1   4
1   6
1   7
1   10
2   3
2   9
2   10
3   4
4   7
9   10

我需要确定最小的一组值,以便 df 中的每一行至少包含其中一个值。

从上面的df期望out是:

1
2
4
9

我有一个有效的过程,但速度非常慢。有没有办法可以更快地执行此操作或并行化该过程?

x=1  
while [ $x -gt 0 ]  
do  
    i=$(paste df | tr '\t' '\n' | sort | uniq -c | 
        sort -r -k1,1 -k2,2n | awk 'NR==1{print $2}')  
    echo $i >> out  
    grep -vw $i df > tmpdf  
    cat tmpdf > df  
    x=$(paste df | wc -l)  
done

答案1

这是一些“线路噪音”perl:

perl -lane '
        for $f (@F) {push @{$x{$f}}, $.}                          # 1.
    } END {
        use List::Util qw/any first/;
        sub sort_by_count_desc {
            map  { $_->[0] } 
            sort { $b->[1] <=> $a->[1] || $a->[0] <=> $b->[0] } 
            map  { [$_, scalar(@{$x{$_}})] } 
            @_ 
        }
        @ordered = sort_by_count_desc(keys %x);                   # 2.
        %result = ();
        for ($i=1; $i<=$.; $i++) {                                # 3.
            $node = first { any {$_ == $i} @{$x{$_}} } @ordered;  # 4.
            $result{$node} = 1;
        }
        print join "\n", sort_by_count_desc(keys %result);
' df

在哪里

  1. 循环遍历文件的行并将每个值映射到它出现的行列表
  2. 创建按外观列表大小降序排列的值的有序行
  3. 循环遍历行号范围和 foreach 行号
  4. 查找出现行号的第一个值

这输出

1
2
4
10

答案2

这是一个“哑巴”Linux使用 进行优化bash,但它不是特别可移植并且不会改进算法:

f=$(mktemp) ; cp df $f
while [ -s $f ]  ; do   
    tr '\t' '\n' < $f | sort | uniq -c | sort -r -k1,1 -k2,2n | 
    grep -om1 '\S$' | tee >(grep -vwf - $f | sponge $f)
done
rm $f

笔记:

  • 使用df输入文件作为暂存器是不好的做法,请改用mktemp

  • 输出转到标准输出。如果需要,请更改done为。done > out

  • spongeutil 不再需要命名tmpdf文件。

  • 使用teeandgrep -f -代替$i搜索字符串变量。

  • 检查是否wc -l0不需要;test -s足够了。

相关内容