суммы столбцов на основе совпадающих полей

Я столкнулся с проблемой, которая превосходит мои базовые знания в UNIX и действительно будет очень полезной. У меня большой файл в следующем формате:

2 1019 0 12 2 1019 3 0 2 1021 0 2 2 1021 2 0 2 1022 4 5 2 1030 0 1 2 1030 5 0 2 1031 4 4 

Если значения в столбце два совпадают, я хочу суммировать значения в столбцах 3 и 4 обеих строк, иначе просто сумма значений в уникальной строке.

Поэтому вывод, на который я надеюсь, будет выглядеть так:

 2 1019 15 2 1021 4 2 1022 9 2 1030 6 2 1031 8 

Я могу сортировать файлы по столбцу 2 с awk или сортировать и суммировать последние столбцы с awk, но только для отдельных строк не для двух строк, где соответствует столбец 2.

Я бы сделал это в Perl:

 $ perl -lane '$k{"$F[0] $F[1]"}+=$F[2]+$F[3]; END{print "$_ $k{$_}" for keys(%k) }' file 2 1019 15 2 1021 4 2 1030 6 2 1031 8 2 1022 9 

Или awk:

 awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 

Если вы хотите, чтобы результат сортировался в соответствии со вторым столбцом, вы можете просто sort трубку:

 awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file | sort -k2 

Обратите внимание, что оба решения включают в себя 1-й столбец. Идея состоит в том, чтобы использовать первый и второй столбцы как ключи к хешу (в perl) или ассоциативный массив (в awk). Ключ в каждом решении – column1 column2 поэтому, если две строки имеют один и тот же столбец два, но другой столбец один, они будут сгруппированы отдельно:

 $ cat file 2 1019 2 3 2 1019 4 1 3 1019 2 2 $ awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 3 1019 4 2 1019 10 

Может быть, это может помочь, но столбец 1 всегда 2, и результаты зависят от него?

 awk '{ map[$2] += $3 + $4; } END { for (i in map) { print "2", i, map[i] | "sort -t't'" } }' file 

или, как упоминалось Гленн Джекман в комментариях по поводу сортировки:

 gawk '{ map[$2] += $3 + $4; } END { PROCINFO["sorted_in"] = "@ind_str_asc"; for (i in map) { print 2, i, map[i] } }' file 

Вы можете предварительно отсортировать данные и позволить awk обрабатывать детали:

 sort -n infile | awk 'NR>1 && p!=$2 {print p,s} {s+=$3+$4} {p=$2}' 

Вывод:

 1019 15 1021 19 1022 28 1030 34 

Если вы действительно хотите сохранить первый столбец, сделайте следующее:

 sort -n infile | awk 'NR>1 && p!=$1FS$2 {print p,s} {s+=$3+$4} {p=$1FS$2}' 

Вывод:

 2 1019 15 2 1021 19 2 1022 28 2 1030 34 

объяснение

Переменная p содержит значение $2 предыдущей строки или $1FS$2 во втором случае выше. Это означает, что {print p,s} запускается, когда $2 предыдущей строки не совпадает с той, что находится в текущей строке ( p!=$2 ).