-1

trying to sum elements in an array using bc,i have a file with names and thier vaules if the names appears 3 times i should multiply its value with 3 then find the sum of all the elements together,im seeing standard input error

$ cat foo.txt

max 2.3 
henry 3
fransis 4.5
max 2.3
henry 3
max 2.3

it should show on the terminal

max 6.9
henry 6 
fransis 4.5

then

total 17.9
declare -A array

while read name value; do

     array[$name]=$( echo "${array[$name]:-0} + $value" | bc )

done < cat foo.txt

for name in "${!array[@]}"; do

     echo "$name ${array[$name]}"

done
Eric Wilson
  • 57,719
  • 77
  • 200
  • 270

3 Answers3

1

I'm not sure if you're required to use bc but this could be done with the following awk command:

awk '{names[$1]=$1;vals[$1]+=$2} END {for(i in names){sum+=vals[i];print i, vals[i]}; print "total " sum}' foo.txt
telenachos
  • 884
  • 6
  • 18
  • i was trying to see how bc can do it – thequantumtheories Dec 07 '11 at 16:47
  • dude i was trying your code and it worked perfectly is it ok for you to explain the code im new to awk i would like to know whats going on in this code you wrote for me – thequantumtheories Dec 11 '11 at 21:02
  • The first part tells awk what to do for each record in the file: {names[$1]=$1;vals[$1]+=$2}. This will store the values of the first column ($1) in an array called names[]. It also keeps a running sum of the second column ($2) for each name in the first column in the array vals[]. – telenachos Dec 12 '11 at 17:36
  • The second part tells awk what to do after processing all the lines: END {for(i in names){sum+=vals[i];print i, vals[i]}; print "total " sum}. This will loop through the items in names[] and use each name as an index into the vals[] array. Tallying up the total sum into a variable called sum, as well as printing the name (print i) and printing the indivual sums (print vals[i]). Finally it will print the total sum (print "total " sum). Hope that helps. – telenachos Dec 12 '11 at 17:37
1

In true bash spirit, here's a series of piped commands to achieve this :)

echo 'max 2.3
henry 3
fransis 4.5
max 2.3
henry 3
max 2.3' | \
sort | \
uniq -c | \
while read count name value
  do echo "$name" $(bc <<< "$count * $value")
done | \
sort -r -k 2

sort | uniq -c will count the number of identical lines and produce a list like this:

1 fransis 4.5
2 henry 3
3 max 2.3

This list is passed to a while loop that reads 3 values at a time (read count name value)

For each set of 3 values, it prints the name and the multiplication result:

echo "$name" $(bc <<< "$count * $value")

The result is then sorted so that the highest score is at the top, i.e. reverse sort on the second column:

sort -r -k 2

This all assumes that the input file is "well formed", with no malformed lines or extra whitespace.

Martin
  • 37,119
  • 15
  • 73
  • 82
0

Remove the word cat from the done < cat foo.txt line.

Update: Reomove any empty lines from the input file, too.

choroba
  • 231,213
  • 25
  • 204
  • 289