繁体   English   中英

bash中的数组元素所有组合

[英]Array elements all combinations in bash

我需要帮助来查找 bash 中数组元素的所有组合(总和)。以下是代码的摘录:

    #!/bin/bash
array=("31" "-41" "59" "26" "-53" "58" "97" "-93" "-23" "84") # min 1 vlaue
arrLength=("${#array[@]}")
for (( i=0; i < $arrLength; i++))
do
    #echo "$i"
    for (( j=$i; j > 0; j-- ))
    do
        summ=$(( array[j] ))
        bak=$((array[0] + summ))
        echo "$summ ; $bak"
    done
    echo "_____________________________"
done

这会找到单对和双对。 缺少的是三对(例如 31+(-41)+59)、四对的组合……等等。 我不想对其进行硬编码,因为元素的数量可能会在我的程序中发生变化。

如有帮助,我将不胜感激。 谢谢你。

正如其他人评论的那样,我们有 10 个数字的 1023 种组合,不包括空集。 这些组合可以与00000000011111111111之间的位模式相关联。 那么请你试试:

#!/bin/bash

array=("31" "-41" "59" "26" "-53" "58" "97" "-93" "-23" "84")
n=${#array[@]}                          # number of elements
for (( i = 1; i < (1 << n); i++ )); do  # loop between 1 and 1023
    sum=0; list=()                      # initialize variables
    for (( j = 0; j < n; j++ )); do     # loop over the bit slice position
        if (( (1 << j) & i )); then     # if the bit is set
            (( sum += ${array[j]} ))    # then pick the element to sum
            list+=("${array[j]}")       # append to an array to report
        fi
    done
    (IFS=,; printf "(%s) = %d\n"  "${list[*]}" "$sum")
                                        # report the sum of the set
done

output 的前几行:

(31) = 31
(-41) = -41
(31,-41) = -10
(59) = 59
(31,59) = 90
(-41,59) = 18
(31,-41,59) = 49
<snip>

它将总共打印 1023 行。

一个awk使用递归 function 的想法:

array=("31" "-41" "59" "26" "-53" "58" "97" "-93" "-23" "84")

printf "%s\n" "${array[@]}" |
awk '
function find_sum(i, sum, label,    j) {

      printf "%8s = %s\n",sum,label

      for (j=i+1;j<=FNR;j++)
          find_sum(j, sum+item[j], label " + " item[j])
}

    { item[FNR]=$1 }

END { for (i=1;i<=FNR;i++)
          find_sum(i, item[i], item[i])
    }
'

注意:由于我们使用单个awk调用执行所有操作,因此我们可以将总运行时间从约 13 秒( bash循环构造)减少到约 0.1 秒( awk

这会产生:

      31 = 31
     -10 = 31 + -41
      49 = 31 + -41 + 59
      75 = 31 + -41 + 59 + 26
      22 = 31 + -41 + 59 + 26 + -53
      80 = 31 + -41 + 59 + 26 + -53 + 58
     177 = 31 + -41 + 59 + 26 + -53 + 58 + 97
      84 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -93
      61 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -93 + -23
     145 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -93 + -23 + 84
     168 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -93 + 84
     154 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -23
     238 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + -23 + 84
     261 = 31 + -41 + 59 + 26 + -53 + 58 + 97 + 84
     -13 = 31 + -41 + 59 + 26 + -53 + 58 + -93

... snip ...

      35 = 58 + -23
     119 = 58 + -23 + 84
     142 = 58 + 84
      97 = 97
       4 = 97 + -93
     -19 = 97 + -93 + -23
      65 = 97 + -93 + -23 + 84
      88 = 97 + -93 + 84
      74 = 97 + -23
     158 = 97 + -23 + 84
     181 = 97 + 84
     -93 = -93
    -116 = -93 + -23
     -32 = -93 + -23 + 84
      -9 = -93 + 84
     -23 = -23
      61 = -23 + 84
      84 = 84

如果您的 memory 可以容纳它,则通过使用添加的新项目复制它来将每个新项目的数组加倍。 该解决方案依赖于包含空集(总和为0 )来进行初始化。 要排除它,请在最后将其剥离。

a=(31 -41 59 26 -53 58 97 -93 -23 84)
b=(0)
for i in ${a[@]}; do for j in ${b[@]}; do b+=( $((i+j)) ); done; done
$ echo ${#b[@]}
1024

$ printf '%s\n' ${b[@]}
0
31
-41
-10
59
:
:
86
155
186
114
145

同样的方法包括计算步骤:

a=(31 -41 59 26 -53 58 97 -93 -23 84)
b=("0 = 0")
for i in ${a[@]}; do for j in "${b[@]}"; do b+=("${j%=*}+ $i = $((i+${j#*=}))"); done; done
$ echo ${#b[@]}
1024

$ printf '%s\n' "${b[@]}"
0 = 0
0 + 31 = 31
0 + -41 = -41
0 + 31 + -41 = -10
0 + 59 = 59
:
:
0 + 31 + -41 + 26 + -53 + 58 + 97 + -93 + -23 + 84 = 86
0 + 59 + 26 + -53 + 58 + 97 + -93 + -23 + 84 = 155
0 + 31 + 59 + 26 + -53 + 58 + 97 + -93 + -23 + 84 = 186
0 + -41 + 59 + 26 + -53 + 58 + 97 + -93 + -23 + 84 = 114
0 + 31 + -41 + 59 + 26 + -53 + 58 + 97 + -93 + -23 + 84 = 145

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM