Policz sumę każdej kolumny w pliku

9

W pliku z różną liczbą kolumn rozdzielonych spacją '', Jak policzyć sumę kolumn. Przykład pokazuje potrzebę:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Wówczas wynik będzie:

  • dla kolumny 1 (1 + 2 + 4 + 1) = 8
  • dla kolumny 2 jest 11
  • dla kolumny 3 jest 7
  • dla kolumny 4 jest 5
Maythux
źródło

Odpowiedzi:

12

Za pomocą awk

awk '{for (i=1;i<=NF;i++) sum[i]+=$i;}; END{for (i in sum) print "for column "i" is " sum[i];}' FileA
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5
steeldriver
źródło
Dobre wykorzystanie tablic, choć myślę, że można to uprościć, licząc sumę i drukując ją od razu
Sergiy Kolodyazhnyy
Rzeczywiście jest to najlepsza odpowiedź tutaj.
kos
5

Użyj numsumdo tego zadania i oddziel przetwarzanie danych od wyników.

Zainstaluj num-utils, potrzebujemynumsum

sudo apt-get install num-utils

I zacznij od

numsum -c <your_file_name>

Przykład

$ cat "File A"
1 2 
2 3
4 5 6 
1 1 1 5

$ numsum -c "File A"
8 11 7 5

lub w wybranym formacie:

$ numsum -c "File A" | awk '{for(i=1;i<=NF;i++) {print "for column "i" is "$i}}'
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5

od man numsum

-c      Print out the sum of each column.

przykłady z man numsum

EXAMPLES

   Add up the 1st, 2nd and 5th columns only.

       $ numsum -c -x 1,2,5 columns
       15 40 115

   Add up the rows of numbers of a file.

        $ numsum -r columns
        55
        60
        65
        70
        75
AB
źródło
3
#!/bin/sh

while read a b c d; do
    col1=$((col1 + a))
    col2=$((col2 + b))
    col3=$((col3 + c))
    col4=$((col4 + d))
done < File_A

echo $col1 $col2 $col3 $col4
Florian Diesch
źródło
Prawdopodobnie można powiedzieć (( col1 += a )), itp. Również echo "..."jest bezpieczniejszy, a takżewhile IFS= read -r ...
fedorqui
@fedorqui echomożna bezpiecznie używać w ten sposób do echa liczb, $IFSdomyślnie w białych znakach i te powinny być liczbami, więc nie trzeba zajmować się odwrotnymi ukośnikami. Jedynym minusem tej odpowiedzi jest potrzeba znajomości liczby kolumn przed wykonaniem.
kos
@kos nigdy nie wiadomo, jak plik wejściowy może być. I pomimo tego, że PO wymienia tylko liczby, zawsze dobrą praktyką jest przygotowanie się na gorsze. Zobacz Jak mogę odczytać plik (strumień danych, zmienna) wiersz po wierszu (i / lub pole po polu)? dla wspaniałego wyjaśnienia.
fedorqui
@fedorqui Na własne oświadczenie Myślałem, że to nie jest dyskusja; Jeśli chcesz zdobyć punkty, zakładając, że plik wejściowy może zawierać coś innego niż liczby, brakuje ci rażącej części: sprawdzanie, czy to, co jest czytane, jest liczbą. Dodawanie ciągów i używanie echo "[...]"do prawidłowego drukowania tego, czego nie chcesz wyświetlać, nie ma sensu.
Kos
@kos Możesz oczywiście powiedzieć echo $vari while read a b c, to działa tutaj. Jednak przyzwyczaisz się do pisania go słabo i pewnego dnia wystąpią dziwne błędy podczas przetwarzania bardziej złożonego pliku. Wtedy zauważysz, że cytowanie zmiennych i używanie while IFS= read -r ...było bezpieczniejsze i powiesz: „o tak, fedorqui miał rację, mam nadzieję, że mógłbym go mieć i przytulić, by okazać wdzięczność!”.
fedorqui
3

Sądząc po komentarzach do własnej odpowiedzi, chcesz tylko sumę jednej kolumny na raz. Jeśli tak, oto nie-awk sposób, aby to zrobić:

cut -d' ' -f3 FileA | grep . | paste -s -d+ | bc

gdzie zastąpiłbyś 3numer kolumny, którą jesteś zainteresowany.

Cyfrowa trauma
źródło
0

Oto jednoliniowe podejście do skryptu Perl. Zależy to od użycia -aflagi, która umożliwia automatyczne dzielenie aktualnie czytanej linii z -nflagą na tablicę @F. Wszystko, co musimy zrobić, to iterować te elementy i dodawać je do odpowiedniego indeksu w $sumtablicy, a zatem każdy element tablicy jest sumą dla każdej odpowiedniej kolumny. Na koniec wypisujemy wynik w ENDbloku kodu.

$ perl -lane '$j=0;foreach $i (@F){$sum[$j]+=$i; $j+=1;}; END{print join("\n",@sum)} ' input.txt                                                     
8
11
7
5

Alternatywnie, oto pełne podejście do skryptu Perla. Polega na podzieleniu każdej linii na tablicę i iteracji po każdym elemencie w tej tablicy, dodając każdą liczbę do odpowiedniej pozycji w @sumstablicy. Skrypt drukuje każdą linię, a następnie generuje raport dla każdej kolumny. Drukowanie każdej linii można usunąć, dodając #wcześniejprintf("%s",$line);

#!/usr/bin/env perl
use strict;
use warnings;

open(my $fh,"<",$ARGV[0]); 
my $i = 0;
my @sums;

while(my $line = <$fh>) { 
    printf("%s",$line);
    my @nums = split(" ",$line);
    my $j = 0;
    foreach my $num (@nums){
        $sums[$j] += $num;
        $j += 1;
    }

}

my $k = 0;
foreach my $sum (@sums){
    printf("- column %d sum: %d\n",$k,$sum);
    $k+=1;
}

close($fh);

Użycie jest proste chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Na przykład:

$ ./sum_columns_2.pl input.txt                                                                                                                       
1 2 
2 3
4 5 6 
1 1 1 5
- column 0 sum: 8
- column 1 sum: 11
- column 2 sum: 7
- column 3 sum: 5
Sergiy Kolodyazhnyy
źródło
-2

Proste rozwiązanie:

awk '{sum += $i} END {print sum}' file

Zamień i na numer kolumny, na przykład kolumna 1:

awk '{sum += $1} END {print sum}' file

wyjście to:

8
Maythux
źródło
3
Otrzymasz tylko jedną kolumnę. Nie spełniasz swojej specyfikacji.
Oli
Nie stwierdziłem, że chcę uzyskać wszystkie wyniki w tym samym poleceniu. plus ta odpowiedź potrzebuje tylko pętli i będzie idealna
Maythux,
Więc po co głosować?
Maythux,