![查找文件的每一行中至少存在一个值的最小值集](https://linux22.com/image/135949/%E6%9F%A5%E6%89%BE%E6%96%87%E4%BB%B6%E7%9A%84%E6%AF%8F%E4%B8%80%E8%A1%8C%E4%B8%AD%E8%87%B3%E5%B0%91%E5%AD%98%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%80%BC%E7%9A%84%E6%9C%80%E5%B0%8F%E5%80%BC%E9%9B%86.png)
我有一个像这样的文件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
在哪里
- 循环遍历文件的行并将每个值映射到它出现的行列表
- 创建按外观列表大小降序排列的值的有序行
- 循环遍历行号范围和 foreach 行号
- 查找出现行号的第一个值
这输出
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
这
sponge
util 不再需要命名tmpdf文件。使用
tee
andgrep -f -
代替$i
搜索字符串变量。检查是否
wc -l
是0不需要;test -s
足够了。