如何在 bash 中进行反连接或逆连接

如何在 bash 中进行反连接或逆连接

我想执行一些数据分析软件所谓的反连接:从一个列表中删除与另一个列表中的行匹配的行。这是一些玩具数据和预期输出:

$ echo -e "a\nb\nc\nd" > list1
$ echo -e "c\nd\ne\nf" > list2
$ antijoincommand list1 list2
a
b

答案1

我不会使用join它,因为join需要对输入进行排序,这对于这样一个简单的工作来说是不必要的复杂化。您可以改为使用grep

$ grep -vxFf list2 list1
a
b

或者awk

$ awk 'NR==FNR{++a[$0]} !a[$0]' list2 list1
a
b

如果文件已经排序,则替代方法join -v 1comm -23

$ comm -23 list1 list2 
a
b

答案2

使用该实用程序执行此操作的一种方法join是:

$ join -v 1 list1 list2
a
b

从联机帮助页:

-A文件号

:还打印文件 FILENUM 中不可配对的行,其中 FILENUM 为 1 或 2,对应于 FILE1 或 FILE2

-v文件号

: 喜欢-AFILENUM,但抑制连接的输出行

答案3

使用(以前称为 Perl_6)

Raku 具有Set对象类型,您可以读取单个文件以从以下行创建集合:

~$ raku -e 'my $a = Set.new: "list1".IO.lines; 
            my $b = Set.new: "list2".IO.lines; 
            say "list1 = ", $a;
            say "list2 = ", $b;'
list1 = Set(a b c d)
list2 = Set(c d e f)

您可以使用 ASCII 中缀(-)或 Unicode 中缀执行非对称集差异

~$ raku -e 'my $a = Set.new: "list1".IO.lines; 
            my $b = Set.new: "list2".IO.lines; 
            say $a (-) $b;'
Set(a b)
~$ raku -e 'my $a = Set.new: "list1".IO.lines; 
            my $b = Set.new: "list2".IO.lines; 
            say $b (-) $a;'
Set(e f)

OTOH,有时您需要执行对称的设置差异,Raku 满足您的需求。使用 ASCII 中缀(^)或 Unicode 中缀

~$ raku -e 'my $a = Set.new: "list1".IO.lines; 
            my $b = Set.new: "list2".IO.lines; 
            say $a (^) $b;'
Set(a b e f)

最后,您可以通过将最后一行更改为.keys.put for... 来获得逐行输出。
最终的对称的下面使用 Unicode 中缀运算符设置差异示例:

~$ raku -e 'my $a = Set.new: "list1".IO.lines;
            my $b = Set.new: "list2".IO.lines;
            .keys.put for $a ⊖ $b;'
f
e
a
b

https://docs.raku.org/type/Set
https://docs.raku.org/language/setbagmix#Operators_with_set_semantics
https://raku.org

相关内容