Bashで配列とそのインデックスの重複エントリを見つける

Bashで配列とそのインデックスの重複エントリを見つける

bashを使って配列内の重複するエントリとそのインデックスを見つけたいと思います。
たとえば、次の配列があります。

arr=("a" "b" "c" "a" "c")

この場合、インデックス0と3では「a」が繰り返され、インデックス2と4では「c」も繰り返される。

現在、2つのネストされたループを使用していますが、特に大きな配列の場合、速度が遅すぎます。
Bashでこれを行うより良い効率的な方法はありますか?

ありがとうございます!

答え1

awkを使用して配列要素を入力として使用します。

$ printf '%s\n' "${arr[@]}" |
  awk '{ elmnt[$0]= ($0 in elmnt? elmnt[$0] FS:"") NR-1 }
  END{ for (e in elmnt) print e, elmnt[e] }'
a 0 3
b 1
c 2 4

新しい要件の場合(各結果をシェル変数に保存):

$ printf '%s\n' "${arr[@]}" |
  awk -v q="'" '{ elmnt[$0]= ($0 in elmnt? elmnt[$0] FS:"") NR-1 }
  END{ for (e in elmnt) print e, q elmnt[e] q }' OFS='='
a='0 3'
b='1'
c='2 4'

上記のコマンド出力をファイルに保存してからexport varfilevarfileファイル名のみ)を使用してファイルをエクスポートすると、すべての変数がシェル変数としてエクスポートされます。

答え2

毎回線形スキャンに依存することなく、連想配列を使用して値が表示されていることを確認できます。

#!/bin/bash
arr=("a" "b" "c" "a" "c")
declare -A values=()
for v in "${arr[@]}"; do
    if [ "${values["x$v"]+set}" = set ]; then
        echo "value '$v' is duplicate"
        break
    fi
    values["x$v"]=1
done 
unset values

単にawk処理された値をダンプするのと比較して、どれだけ速いかは問題のサイズによって異なります。シェルは高速ではありません。特にBashは非常に遅いです。

関連情報