Bash

如何減去兩個列表(快速)?

  • May 14, 2018

什麼是減去兩個列表的快速方法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 )

如何從 list1 中刪除 list2 的所有元素以獲得結果列表 ( listr) 等效於:

listr=( 4 6 10 )

列表也可以在文件中,如果列表很大(它可能使用太多記憶體)應該如此。

為了使這個問題簡短,我將所有算法都放在社區答案中。

請閱讀其中完成的多項測試。

多組

最初的問題是要在 list2 中找到完整列表 (list1) 的缺失元素,不重複。

但是,如果列表是:

list1=( a a b b b c     d d   )
list2=(     b b   c c c d d e )

並且多集減法的定義本頁所示,預期結果為:

listr= ( a a b )

只有算法 1 和 3 可以正常工作。

算法 2 或 4 都不能做到這一點。

算法 5(comm)可以通過做comm -23.

算法 6 (zsh) 失敗。我不知道如何使它工作。

算法 7(通信)。如上所述,使用-23作品。

我沒有分析Set symmetric difference定義的所有算法,它應該產生:

listr=( a a b c c e )

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


1是的,我知道在 shell 中處理文本文件(行列表)是個壞主意,它的設計速度很慢。

但也有似乎無法避免的情況。

我(我們)對建議持開放態度。

您可以使用comm刪除兩個列表共有的任何內容:

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

這將按comm預期順序對兩個列表進行排序,比較它們,僅輸出對任一列表唯一的項目,然後按數字順序再次對它們進行排序。

如果兩個列表都按字典順序排序(根據LC_COLLATE),則可以避免再次排序:

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

如果您需要比較的值儲存在文件中,這也很有效。

引用自:https://unix.stackexchange.com/questions/443575