I need help to find all combinations (sum) of array elements in bash. here is an excerpt from the code:
#!/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
This finds the single pairs and the double pairs. What is missing are the three-pairs (e.g. 31 (-41) 59), the combinations of four...and so on. I don't want to hard code it, because the number of elements can change in my program.
For help I would be very grateful. Thank you.
CodePudding user response:
As commented by others, we have 1023 combinations for 10 numbers, excluding
the empty set. These combinations can be associated with the bit pattern
between 0000000001 and 1111111111. Then would you please try:
#!/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
First few lines of the output:
(31) = 31
(-41) = -41
(31,-41) = -10
(59) = 59
(31,59) = 90
(-41,59) = 18
(31,-41,59) = 49
<snip>
It will print 1023 lines in total.
CodePudding user response:
One awk idea using a recursive 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])
}
'
NOTE: since we perform all operations with a single awk call we can reduce the total run time from ~13 seconds (bash looping construct) to ~0.1 second (awk)
This generates:
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
