如何使用awk基于两列查找唯一值

时间:2019-05-06 10:42:12

标签: linux shell awk unique

考虑我有一个测试文件(test.txt)包含的数据为

1,2 
2,3 
2,1 
2,2 
3,1 
1,3 
2,5
4,1

我希望每对删除重复项,例如对于(1,2)和(2,1)对,应打印其中一个(先到先打印)。预期输出为

1,2
2,3
3,1
2,2
2,5
4,1

我已经尝试过awk -F"," '!seen[$1,$2]++ && !seen[$2,$1]' test.txt这个命令。它显示为

1,2
2,3
3,1
2,5
4,1

为什么对2,2不打印?还有如何获得预期的输出。

4 个答案:

答案 0 :(得分:2)

如前所述,问题来自逻辑评估中的短路。

要避免这种情况,一种选择是在2D表seen中测试并设置一个单一值:

awk -F"," '!seen[($1<$2?$1:$2)+0, ($1>$2?$1:$2)+0]++'

基本上,它使用两个值中的最小值和最大值作为索引,因此是一个测试而不是两个测试,然后增加插槽。

请注意+0指令,该指令强制转换为整数。之所以必须这样做,是因为字段包含了额外的空格,包括最终的行尾。

答案 1 :(得分:1)

在任何UNIX机器上的任何外壳中都有任何awk的通用,惯用的2字段解决方案:

$ awk -F, '!seen[$1>$2 ? $1 FS $2 : $2 FS $1]++' file
1,2
2,3
2,2
3,1
2,5
4,1

以及使用asort()使用GNU awk的任意数量的字段:

awk -F, '{split($0,a); asort(a); for (i=1;i<=NF;i++) k=(i>1 ? k FS : "") a[i]} !seen[k]++' file

例如对于包含每个1,2,3和2,3,4排列的输入文件:

$ cat file
1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1
2,3,4
2,4,3
3,2,4
3,4,2
4,2,3
4,3,2

$ awk -F, '{split($0,a); asort(a); for (i=1;i<=NF;i++) k=(i>1 ? k FS : "") a[i]} !seen[k]++' file
1,2,3
2,3,4

答案 2 :(得分:0)

我在awk方面并不出色,但是使用其他工具很容易做到这一点。

如果顺序无关紧要,让我们以相反的顺序重复每一行。然后我们可以使用sort -u来打印唯一的行:

cat <<EOF |
1,2
2,3
2,1
2,2
3,1
1,3
2,5
4,1
EOF
sed 's/\(.*\),\(.*\)/\1,\2:\1,\2\n\2,\1:\1,\2/' | 
sort -u -t: -k1,1 |
cut -d: -f2 |
sort -u

sed实用工具转换了这一行:

 1,2

进入:

 1,2:1,2
 2,1:1,2

然后,我使用仅由:sort -u -t: -k1,1分隔的第一列删除重复项。然后cut -d: -f2删除第一列。然后,我再次对唯一行进行排序,因为我们将有重复行(例如,1,21,22,1是唯一的时)。结果是:

1,2
2,2
2,3
2,5
3,1
4,1

答案 3 :(得分:0)

如果顺序不重要,则可以轻松使用 awk 排序 uniq 组合。

awk -F "," '$1 < $2 { printf "%d,%d\n", $1,$2} $2 <= $1 {printf "%d,%d\n", $2, $1}' file | sort | uniq

此处的awk操作通过对数字进行排序来标准化输出,因此2,1将变为1,2