Bash - 迭代关联数组的最后几个元素

Bash - 迭代关联数组的最后几个元素

我试图迭代 bash 脚本中关联数组的最后几个条目 - 在本例中是为了总结它们的值。我尝试过以下方法:

SUM="0"
for last_element in $(printf "%s\n" "${!ELEMENTS[@]}" | tail -100); do
  ELEMENT_SUM="$(echo "scale=5; $SUM +  ${ELEMENTS[$last_elements]}" | bc)"
done

实践中发生的情况是打印$last_element出整个列表(在本例中为 100 个元素),而不是迭代每个元素 - 因此会${ELEMENTS[$last_elements]}失败。

${ELEMENTS[-100]}我尝试了多种方法(例如,包括负索引),但没有成功。我不确定我做错了什么......

任何指示和想法将不胜感激。

谢谢!

答案1

bash 中的关联数组本质上是无序的,因此不存在最后一个元素或最后 100 个元素的概念。

但是,如果想要以伪随机顺序对从数组中提取的 100 个元素的值求和,您可以执行以下操作:

e100=$(printf "%s\n" "${elements[@]}"  | tail -n 100)
sum=$(echo ${e100//$'\n'/+} | bc)
echo $sum

第一行用于printf将关联数组中的 100 个元素存储$elements到变量中$e100,并以换行符分隔。

第二行使用echobash 参数模式替换将所有换行符更改为+符号,然后通过管道将其输入bc以执行计算。结果存储在变量 中$sum

顺便说一句,这使用价值观直接关联数组,无需迭代数组的索引。


有更好的方法可以做到这一点,正如老笑话所说的“好吧,如果你想去那里,我不会从这里开始”,bash 并不是任何类型的数据处理的良好起点。使用 awk 或 perl 或 python 或几乎任何非 shell 的东西。

想必您正在使用浮点数,并且已经意识到 bash 只能进行整数算术,因此您正在使用bc它来解决这个问题。您最好使用一种不需要您解决执行此类基本操作的限制的语言。

答案2

bash 关联数组(您需要最新版本)不支持任意键。它也没有用于对列表进行排序的运算符(您需要它最后的有意义),并且不能进行浮点运算。

在这里,我将使用限制较少的 shell(如 zsh)或适当的编程语言(如 perl)。

#! /usr/bin/perl
use List::Util "sum";

%elements = (
  "foo"  => 1.213,
  "\0\n" => 0x12,
  ''     => -3,
  "bar"  => 1e-2
  ...
);
$sum = sum(map {$elements{$_}} (sort keys %elements)[-100 .. -1]);
#! /bin/zsh -

typeset -A elements
elements=(
  foo     1.213
  $'\0\n' 0x12
  ''      -3
  bar     1e-2
  ...
)
set -o extendedglob
sum=$(( ${(@j[ + ])${(@ko)elements}[-100,-1]/(#m)*/$elements[$MATCH]} ))

这些给出了按字典顺序排序的最后 100 个键的元素总和(memcmp()类似 perl 中的比较,strcoll()类似 zsh 中的比较)。

对于 zsh,值可以是 zsh 识别的任何算术表达式,但当我们最终构建一个value1 + value2 + ...供 zsh 求值的表达式时,请注意优先级。

例如,如果value1isvar = 3value2is 4 || hash[$(some-cmd)],最终会进行评估var = 3 + 4 || hash[$(some-cmd)](并且some-cmd将被执行),因此您可能需要确保值被包围,(...)如果它们不仅仅是数字。

相关内容