我有一个包含四列的文件:
text1 a1 a2 5
text2 b2 b8 10
text3 b9 b4 15
text3 b9 b4 25
text3 b9 b4 20
text4 h1 g8 50
text4 g1 k5 70
text4 g1 k5 80
text4 g1 k5 50
text5 y5 p3 25
我想要以下结果:
text1 a1 a2 5
text2 b2 b8 10
text3 b9 b4 25
text4 h1 g8 50
text4 g1 k5 80
text5 y5 p3 25
从匹配的行中删除重复的值:第一、第二和第三列相同,并在第四列取最高值。
我尝试如下:
awk '!x[$1]++' file.txt
您只是在建立索引,
$1
但您的问题要求键为$1
..$3
,并且显然您的尝试并没有选择该键的最大值而不是第一个值。如果某个键的值始终相邻,则可以收集它们直到到达下一个键,然后打印前一个键的最大值。
我们在 中收集前三列
k
,并在 中收集此键的最大值s
。包含最大值的整行是,v
这样我们就不必将键和值组合起来进行打印。脚本通常在找到新键时为前一个键打印一行,但当然,当我们超出文件末尾时,我们也需要这样做,所以我们在块中执行此操作END
。如果无法保证相邻单元格,对文件进行排序并通过管道传输到 Awk 可能比编写更好的脚本更容易,特别是如果您还没有学过任何 Awk。(虽然确实要花一两个小时;但这是对你时间的良好利用。)
首先使用 排序文件
sort
,按字段 1-3 的 ASCII 格式排序,然后按字段 4 的数值格式从高到低排序。然后使用 Perl 单行代码在字段 1-3 中具有相同值的数据中选择第一行。由于之前的排序顺序,第一行将包含每个组的最大值。在这里,我假设输入文件是 TAB 分隔的:Perl 单行命令使用下列命令行标志::
-e
告诉 Perl 在行内查找代码,而不是在文件中。-n
:一次循环输入一行,$_
默认将其分配给。 :在行内执行代码之前-l
删除输入行分隔符(默认在 *NIX 上),并在打印时附加它。 :在空格或选项中指定的正则表达式上拆分成数组。:在 TAB 上拆分,而不是在空格上。"\n"
-a
$_
@F
-F
-F'/\t/'
@F
参见:
perldoc perlrun
:如何执行 Perl 解释器:命令行开关将 any
sort
与 any 一起使用awk
:或者为了获得与问题中所示的相同的输出顺序,只需
| sort
在最后添加另一个(根据需要添加选项),例如: