Criando array associativo baseado em outro array associativo

0

Eu fiz um array associativo como segue. Para dar alguns detalhes, as chaves referem-se a arquivos específicos porque eu usarei esse array no contexto de um script maior (onde o diretório contendo os arquivos será um argumento 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

Até agora, esse array parece se comportar como eu esperava. Agora, quero construir outro array associativo com base nesse array. Para ser específico: meu segundo array terá as mesmas chaves do meu primeiro, mas eu quero dividir os valores por uma variável chamada $ MIN.

Não sei qual das estratégias a seguir é melhor e não consigo fazer nenhum trabalho.

Estratégia 1 : copiar a matriz e modificar a matriz?

MIN=33285268

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

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

Não é isso que eu quero para as chaves. Mesmo se funcionar, eu precisaria executar a operação que mencionei em todos os valores.

Stragegy 2 : constrói o segundo array quando faz o loop através do primeiro.

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

Obrigado

    
por m93 24.08.2018 / 13:54

2 respostas

4

Construa o novo array do antigo:

MIN=33285268

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

Comentários no seu código:

  • Seu primeiro código sugerido não funciona, pois copia os valores do array associativo para o novo array. Os valores obtêm automaticamente as chaves 0, 1 e 2, mas as chaves originais não são copiadas. Você precisa copiar a chave da matriz pela chave, como mostrei acima. Dessa forma, você atribui o valor desejado à chave correta.

  • Seu segundo código sugerido contém um erro de sintaxe, pois possui espaços em torno de = em uma atribuição. É aí que os erros que você vê vêm. variable = value é interpretado como "o comando variable executado com os operandos = e value ".

  • Se você deseja iterar sobre um conjunto de nomes de caminho, não use ls . Em vez disso, basta fazer for pathname in "$BAMFILES"/*bam; do .

  • Cite suas expansões de variáveis.

  • Considere usar printf em vez de echo para gerar dados variáveis.

Relacionados:

por 24.08.2018 / 14:02
1

Para responder à pergunta mais geral sobre a cópia de matrizes associativas.

Os mantenedores bash tomaram a infeliz decisão de copiar a API ksh93 em vez da zsh quando eles introduziram seus próprios arrays associativos na versão 4.0.

ksh93 / bash suporta a configuração de um array associativo como um todo, mas é com:

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

sintaxe. Enquanto com zsh , é

hash=(k1 v1 k2 v2)

(suporte para a sintaxe ([k]=v...) ksh93 também foi adicionado mais tarde para compatibilidade).

O que isso significa, porém, é que com o ksh93 e o bash, é muito complicado criar um hash dessa forma a partir de uma lista arbitrária de chaves e valores.

Com a sintaxe zsh , você só precisa passar a lista como chaves e valores alternados. Por exemplo, para copiar duas matrizes associativas:

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

Ou de um CSV com duas colunas:

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

Ou a partir de conjuntos de chaves e valores:

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

Com a sintaxe ksh93 / bash , enquanto há "${!h[@]}" e "${h[@]}" para expandir para a lista de chaves e valores (como "${(@k)h}" e "${(@v)h}" in zsh ), não há operador para expandir para chaves e valores na sintaxe [key]=value esperada por h=(...) (o "${(@kv)h}" in zsh ).

Um truque que você pode usar nesses shells para copiar matrizes associativas (além de copiar elementos em um loop) é usar a saída de typeset -p .

Por exemplo, o equivalente a zsh ' h2=("${(@kv)h1}") para copiar h1 em h2 poderia ser feito em ksh93 ou bash com:

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

Com qual bash você pode reduzir para:

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

(Embora como em ksh93, typeset -A h=value é a abreviação de typeset -A h=([0]=value) in bash , se value começa com ( e termina com ) , o conteúdo é interpretado como uma atribuição associativa composta como se passado para eval (mesmo se o ( for citado ou o resultado de alguma expansão)).

No final, é mais fácil usar o loop:

for k in "${!h1[@]}"; do h2[$k]=${h1[$k]}; done
    
por 24.08.2018 / 16:19