他の連想配列に基づいて連想配列を作成する

他の連想配列に基づいて連想配列を作成する

以下のように連想配列を作成しました。いくつかの詳細を提供するために、キーは特定のファイルを参照します。これは大きなスクリプトのコンテキストでこの配列を使用するためです(ファイルを含むディレクトリはgetoptsパラメータになります)。

declare -A BAMREADS
echo "BAMREADS array is initialized"

BAMREADS[../data/file1.bam]=33285268
BAMREADS[../data/file2.bam]=28777698
BAMREADS[../data/file3.bam]=22388955

echo ${BAMREADS[@]}  # Output: 22388955 33285268 28777698
echo ${!BAMREADS[@]} # Output: ../data/file1.bam ../data/file2.bam ../data/file3.bam

これまで、この配列は私が期待したように動作するようです。この配列に基づいて別の連想配列を作成したいと思います。具体的には、2番目の配列は最初の配列と同じキーを持ちますが、$ MINという変数で値を分割したいと思います。

次の戦略のどれが最善かわからないし、どちらも正しく機能しないようです。

戦略1:配列をコピーして配列を変更しますか?

MIN=33285268

declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
BAMFRACS=("${BAMREADS[@]}")

echo ${BAMFRACS[@]}  # Output: 22388955 33285268 28777698
echo ${!BAMFRACS[@]} # Output: 0 1 2

これは私が望む鍵ではありません。動作していても、すべての値について述べた作業を行う必要があります。

戦略2:最初の配列を繰り返しながら2番目の配列を設定します。

MIN=33285268

declare -A BRAMFRACS
echo "BAMFRACS array is initialized"

for i in $(ls $BAMFILES/*bam)
do
    echo $i
    echo ${BAMREADS[$i]}
    BAMFRACS[$i] = ${BAMREADS[$i]} 
done

echo ${BAMFRACS[@]}
echo ${!BAMFRACS[@]}


#When I run this, I get the following error which I am unsure how to solve:

../data/file1.bam
33285268
script.bash: line 108: BAMFRACS[../data/file1.bam]: No such file or directory
../data/file2.bam
28777698
script.bash: line 108: BAMFRACS[../data/file2.bam]: No such file or directory
../data/file3.bam
22388955
script.bash: line 108: BAMFRACS[../data/file3.bam]: No such file or directory

ありがとう

答え1

連想配列のコピーに関するより一般的な質問に答えます。

管理者が4.0で独自の連想配列を導入したとき、bashzsh APIの代わりにksh93 APIをコピーするという不幸な決定を下しました。

ksh93/bashは連想配列の設定を完全にサポートしますが、次のものと一致しません。

hash=([k1]=v1 [k2]=v2)

通事論。時間が経つとzshそうです。

hash=(k1 v1 k2 v2)

([k]=v...)ksh93構文のサポートは後で互換性のために追加されました)。

しかし、これはksh93とbashを使用して任意のキーと値のリストからハッシュを生成するのが非常に難しいことを意味します。

zsh構文を使用すると、リストをキーと値を交互に渡すだけです。たとえば、2 つの連想配列をコピーするには、次のようにします。

h2=("${(@kv)h1}")

または2つの列を持つCSVでは:

IFS=$'\n,'; h=($(<file.csv))

またはキーと値の配列から:

h=("${(@)keys:^values}")

ksh93/構文を使用するbashと、キーと値のリスト(たとえば、inなど)に拡張できる"${!h[@]}"andがありますが、目的の構文の(in)キーと値に拡張できる演算子はありません。"${h[@]}""${(@k)h}""${(@v)h}"zsh[key]=valueh=(...)"${(@kv)h}"zsh

ループ内の要素をコピーするのではなく、連想配列をコピーするためにこれらのシェルで使用できる1つの方法はtypeset -p

たとえば、次のようにコピーと同じ操作をzsh実行できます。h2=("${(@kv)h1}")h1h2ksh93bash

h1_definition=$(typeset -p h1) &&
  eval "typeset -A h2=${h1_definition#*=}"

bash次のように短縮できます。

h1_definition=$(typeset -p h1) &&
  typeset -A h2="${h1_definition#*=}"

(ksh93のようにtypeset -A h=valueinの省略形ですが、開始して終了した場合、内容は(参照されているか、一部の拡張の結果であっても)渡されたかのように複合関連付け割り当てとして解釈されます。typeset -A h=([0]=value)bashvalue()eval(

最後に、ループを使用するのも簡単です。

for k in "${!h1[@]}"; do h2[$k]=${h1[$k]}; done

答え2

古い配列から新しい配列を作成します。

MIN=33285268

declare -A BRAMFRACS
for key in "${!BAMREADS[@]}"; do
    BRAMFRACS[$key]=$(( ${BAMREADS[$key]} / MIN ))
done

コードに関するコメント:

  • 最初の提案コードがコピーされたため、機能しません。価値連想配列から新しい配列へ。これらの値は自動的にキー0、1、2を取得しますが、元のキーはコピーされません。上記のようにキーごとに配列をコピーする必要があります。これにより、正しいキーに必要な値を割り当てることができます。

  • =2番目の提案コードには、割り当ての周りにスペースがあるため、構文エラーがあります。ここで見ているエラーが発生します。 「オペランドを使用して実行されるコマンドvariable = value」と解釈されます。variable=value

  • 一連のパス名を繰り返すには、次のようにします。使用しないでくださいls。代わりにfor pathname in "$BAMFILES"/*bam; do

  • 変数拡張を引用してください。

  • 可変データを出力するprintf代わりに使用を検討してください。echo

関連:

答え3

次のbashは、連想配列AA2(設定されていない可能性があります)の値を他の連想配列AA1(ほとんど-Aと宣言する必要があります)に割り当てます。

LIST="$(declare -p AA2 2>/dev/null)"
[[ "$LIST" ]] && AA1+=${LIST#*=}
  • declare -p変数値をdeclareステートメントにエコーすることは、単語分割の問題なしにインタプリタに直接渡すことができます。
  • ${LIST#*=}等号とその前のすべてを削除します。
  • ゼロ以外の長さテスト(2>/dev/null)中にエラー()を非表示にすると、AA2設定を無効にできます。declare[[ "$LIST" ]]
  • AA1またはAA2が連想配列ではない場合、予期しない結果(エラーではない)が発生します。

答え4

これにより、トリックを実行できます(追加のキー値も追加できます)。

declare -A origDict=( [keya]=value_a [keyb]=value_b [keyc]=value_c )
declare -a newDict=( echo ${origDict[*]} [keynew]=new_value )

関連情報