如何减去两个列表(快速)?

ImH*_*ere 8 shell bash ksh zsh

什么是减去两个列表的快速方法1。列表可能很小,可能是 shell 工作中的直接方式。或者列表可能很长,也许外部工具是更快的方法。

假设您有两个列表:

list1=( 1 2 3 4 5 6 7 8 9 10 11 12 )
list2=( 1 2 3   5   7 8 9    11 12 )
Run Code Online (Sandbox Code Playgroud)

如何从 list1 中删除 list2 的所有元素以获得listr等效于的结果列表 ( ):

listr=( 4 6 10 )
Run Code Online (Sandbox Code Playgroud)

列表也可以在文件中,如果列表很大(它可能会使用太多内存),则应该如此。

为了使这个问题简短,我将所有算法放在社区答案中。

请阅读那里完成的多项测试。

多组

最初的问题是为了在 list2 中找到完整列表 (list1) 的缺失元素,没有重复。

但是,如果列表是:

list1=( a a b b b c     d d   )
list2=(     b b   c c c d d e )
Run Code Online (Sandbox Code Playgroud)

多集减法的定义如本页所示,预期结果为:

listr= ( a a b )
Run Code Online (Sandbox Code Playgroud)

只有算法 1 和 3 才能正常工作。
算法 2 或 4 都无法做到这一点。
算法 5 (comm) 可以通过执行comm -23.
算法 6 (zsh) 失败。我不知道如何使它工作。
算法 7(通信)。如上所述,使用-23作品。

我还没有分析应该产生的Set 对称差异定义的所有算法:

listr=( a a b c c e )
Run Code Online (Sandbox Code Playgroud)

但是comm -3 list1.txt list2.txt | tr -d ' \t'有效。


1是的,我知道在 shell 中处理文本文件(行列表)是一个坏主意,它的设计速度很慢。
但有些情况似乎无法避免
我(我们)对建议持开放态度。

Ste*_*itt 11

您可以使用comm删除两个列表共有的任何内容:

listr=($(comm -3 <(printf "%s\n" "${list1[@]}" | sort) <(printf "%s\n" "${list2[@]}" | sort) | sort -n))
Run Code Online (Sandbox Code Playgroud)

这将按comm期望的顺序对两个列表进行排序,比较它们,仅输出对任一列表唯一的项目,然后按数字顺序再次对它们进行排序。

如果两个列表都按字典顺序排序(LC_COLLATE),则可以避免再次排序:

listr=($(comm --nocheck-order -3 <(printf "%s\n" "${list1[@]}") <(printf "%s\n" "${list2[@]}")))
Run Code Online (Sandbox Code Playgroud)

如果您需要比较的值存储在文件中,这也很有效。


llu*_*lua 6

#!/bin/zsh
list1=( 1 2 3 4 5 6 7 8 9 10 11 12 )
list2=( 1 2 3   5   7 8 9    11 12 )
listr=("${(@)list1:|list2}")
typeset -p listr
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

6366 次

最近记录:

7 年,6 月 前