【问题标题】:remove redundancy in a file based on two fields, using awk使用 awk 基于两个字段删除文件中的冗余
【发布时间】:2016-01-25 15:37:35
【问题描述】:

我正在尝试根据前两列的值删除一个非常大的文件(约 100,000 条记录)中的重复行,而不考虑它们的顺序,然后打印这些字段 + 其他列。

所以,从这个输入:

A B XX XX
A C XX XX
B A XX XX
B D XX XX
B E XX XX
C A XX XX

我想要:

A B XX XX
A C XX XX
B D XX XX
B E XX XX

(也就是说,我想删除“B A”和“C A”,因为它们已经以相反的顺序出现;我不在乎接下来的列中的内容,但我也想打印它)

我的印象是使用 awk + ​​数组应该很容易做到这一点,但我无法提供解决方案。

到目前为止,我正在修改这个:

awk '
NR == FNR {
h[$1] = $2   
next
}
$1 in h {
print h[$1],$2}' input.txt

我将第二列存储在由第一列 (h) 索引的数组中,然后检查存储的数组中是否存在第一个字段。然后,打印该行。但是出了点问题,我没有输出。

很抱歉,我的代码一点用都没有,但我有点卡住了。

你有什么想法吗?

非常感谢!

【问题讨论】:

    标签: arrays bash awk


    【解决方案1】:

    如下使用

    $awk '{if( $1$2 in a == 0 && $2$1 in a == 0 ) a[$1$2]=$0; } END{ for(i in a)print a[i]; }' input.txt
    

    说明: 命令正在使用数组键将记录存储在数组 (a) 中,因为数组中尚不存在第一个和第二个字段(即 $1$2 和 $2$1)的组合。读取完整文件后,打印数组 (a)。

    # ($1$2 in a) => checks if there is any key with $1$2 in array a
    # if it's not present then it return 0 
    # and if both combination $1$2 and $2$1 are not present then store the record in array a
    if( $1$2 in a == 0 && $2$1 in a == 0 ) a[$1$2]=$0;
    
    # below print the array a (which stores complete unique record) at the end 
    END{ for(i in a) print a[i]; }'
    

    【讨论】:

    • 你能解释一下你的答案吗?
    • 我修改了答案以添加一些解释
    【解决方案2】:

    只需跟踪两种格式中出现的内容:

    $ awk '!seen[$1,$2]++ && !seen[$2,$1]++' file
    A B XX XX
    A C XX XX
    B D XX XX
    B E XX XX
    

    相当于awk '!(seen[$1,$2]++ || seen[$2,$1]++)' file

    注意它也等同于没有++ 第二个表达式(参见 cmets):

    awk '!seen[$1,$2]++ && !seen[$2,$1]' file
    

    说明

    打印唯一行的典型方法是:

    awk '!seen[$0]++' file
    

    这将创建一个数组seen[],其索引是到目前为止出现的行。因此,如果它是新的,seen[$0] 为 0 并递增为 1。但之前它会被打印,因为表达式 ! var ++ 首先评估 ! var(在 awk 中,True 会触发打印当前行的操作) .当已经看到该行时,seen[$0] 具有正值,因此!seen[$0] 为 false 并且不会触发打印操作。

    在您的情况下,无论顺序如何,您都想跟踪出现的内容,所以我正在做的是将索引存储在两个可能的位置。

    【讨论】:

    • 非常感谢!你能解释一下“seen”命令的语法吗? -- 编辑:我已经看到你已经完成了,谢谢。
    • @EdMorton ops,事实上我只是忘了使用它,有趣的是它可以工作:)
    • @XGrau seen 只是一个关联数组,其中 fedorqui 存储两种不同的值组合,例如:seen["AB"]seen["BA"]。这个名字是任意的——可能是z
    • @EdMorton 你不需要最后一个++。考虑一下:A BA BB A -> !0 && !0!1 && !1!0 && !2。它本来可以很容易地出现在哪里:!0 && !0!1 && !0!0 && !2
    • @dev-null 是的,我终于分解并测试了它,并发现在后续行中 seen[b,a] 已经是之前 seen[a,b]++ 的 1。我更喜欢他们的脚本,因为它更清晰(至少对我来说)。
    猜你喜欢
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 2015-11-07
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多