Bash
如何減去兩個列表(快速)?
什麼是減去兩個列表的快速方法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[@]}")))
如果您需要比較的值儲存在文件中,這也很有效。