1. ホーム
  2. arrays

Bashで2つの配列を比較・差分する

2023-10-12 09:15:23

質問

Bashで2つの配列の差を取ることは可能でしょうか。それを行うための良い方法は何ですか?

コードです。

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" ) 

Array3 =diff(Array1, Array2)

Array3 ideally should be :
Array3=( "key7" "key8" "key9" "key10" )

どのように解決するのですか?

もし、厳密に Array1 - Array2 が必要であれば

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )
Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )

Array3=()
for i in "${Array1[@]}"; do
    skip=
    for j in "${Array2[@]}"; do
        [[ $i == $j ]] && { skip=1; break; }
    done
    [[ -n $skip ]] || Array3+=("$i")
done
declare -p Array3

連想配列でランタイムは改善されるかもしれませんが、個人的には気にしないことにします。 もし、それが問題になるほどのデータを操作するのであれば、shellは間違ったツールです。


Dennisの回答のような対称的な差分の場合、既存のツールである comm のような既存のツールは、入力と出力を少しマッサージする限り、動作します (これらはシェル変数ではなく、行ベースのファイルで動作するため)。

ここでは、配列を単一の文字列に結合するために改行を使用するようシェルに指示し、 から配列に戻すときはタブを破棄します。

$ oldIFS=$IFS IFS=$'\nème'
$ Array3=($(comm -3 <(echo "${Array1[*]}") <(echo "${Array2[*]}"))))
comm: ファイル1がソート順ではありません。
$ IFS=$oldIFS
$ declare -p 配列3
declare -a Array3='([0]="key7" [1]="key8" [2]="key9" [3]="key10")' とします。

文句を言われるのは、字句の並び替えによって comm . しかし、どちらの入力配列も同じようにソートされているので、この警告は無視しても問題ないでしょう。 あなたは key1 < … < key9 > key10 を使って警告を消すか、あるいは --nocheck-order の中に | sort -u の中で、入力配列の順序と一意性を保証できない場合は、置換を処理します。