基于另一个关联数组创建关联数组

基于另一个关联数组创建关联数组

我制作了一个关联数组,如下所示。为了提供一些详细信息,键引用特定文件,因为我将在较大脚本的上下文中使用此数组(其中包含文件的目录将是 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

到目前为止,这个数组的行为似乎符合我的预期。现在,我想基于这个数组构建另一个关联数组。具体来说:我的第二个数组将具有与第一个数组相同的键,但我想将这些值除以一个名为 $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:循环第一个数组时构建第二个数组。

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 中引入自己的关联数组时,他们bash做出了一个不幸的决定,即复制 ksh93 API 而不是 zsh API。

ksh93/bash确实支持将关联数组设置为一个整体,但它与:

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

句法。与 时zsh,它是

hash=(k1 v1 k2 v2)

([k]=v...)为了兼容性,后来还添加了对 ksh93 语法的支持)。

但这意味着,对于 ksh93 和 bash,从任意键和值列表创建哈希是非常棘手的。

使用zsh语法,您只需将列表作为交替键和值传递即可。例如,要复制两个关联数组:

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

或者来自包含两列的 CSV:

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

或者来自键和值的数组:

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

使用ksh93/bash语法时,虽然有"${!h[@]}"and"${h[@]}"可以扩展到键和值的列表(如"${(@k)h}"and "${(@v)h}"in zsh),但没有运算符可以扩展到(in )[key]=value所期望的语法中的键和值。h=(...)"${(@kv)h}"zsh

您可以在这些 shell 中使用的一个技巧来复制关联数组(而不是在循环中复制元素),即使用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 中一样,是intypeset -A h=value的缩写,如果以 开头并以 结尾,则内容将被解释为复合关联赋值,就好像传递给一样(即使被引用或某些扩展的结果))。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,但不会复制原始键。您需要按键复制数组,如我上面所示。这样您就可以将所需的值分配给正确的键。

  • 您的第二个建议代码包含语法错误,因为它=在赋值周围有空格。这就是您看到的错误的来源。 被解释为“使用操作数和执行的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 )

相关内容