Linux Bash подсчитывать и суммировать по уникальным столбцам - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть текстовый файл с такими строками (в Linux Bash):

A B C D
A B C J
E B C P
E F G N
E F G P
A B C Q
H F S L
G Y F Q
H F S L

Мне нужно найти строки с уникальными значениями для первых 3 столбцов, вывести их количество, а затем вывести итоговый последний столбец для каждой уникальной строки, поэтому результат будет следующим:

3 A B C D,J,Q
1 E B C P
2 E F G N,P
1 G Y F Q
2 H F S L

Что я пробовал:

cat FILE | sort -k1,3 | uniq -f3 -c | sort -k3,5nr

Может быть, есть какой-нибудь совет?

Заранее спасибо!

Ответы [ 4 ]

0 голосов
/ 05 сентября 2018

Вы можете использовать GNU datamash:

$ cat input
A B C D
A B C J
E B C P
E F G N
E F G P
A B C Q
H F S L
G Y F Q
H F S L
$ datamash -t' ' --sort groupby 1,2,3 unique 4 count 4 < input
A B C D,J,Q 3
E B C P 1
E F G N,P 2
G Y F Q 1
H F S L 2

Это, к сожалению, выводит счет в последнем столбце. Если это абсолютно необходимо для первого столбца, вам придется переформатировать его:

$ datamash -t' ' --sort groupby 1,2,3 unique 4 count 4 < input | awk '{$0=$NF FS $0; NF--}1'
3 A B C D,J,Q
1 E B C P
2 E F G N,P
1 G Y F Q
2 H F S L
0 голосов
/ 05 сентября 2018

Не могли бы вы попробовать и дайте мне знать, если это поможет вам. Это даст вам вывод в той же последовательности, что и для вхождений $1, $2 и $3 в Input_file.

awk '
!a[$1,$2,$3]++{
  b[++count]=$1 FS $2 FS $3
}
{
  c[$1,$2,$3]=c[$1,$2,$3]?c[$1,$2,$3] "," $4:$0
  d[$1 FS $2 FS $3]++
}
END{
  for(i=1;i<=count;i++){
    print d[b[i]],c[b[i]]
  }
}
' SUBSEP=" "  Input_file
0 голосов
/ 05 сентября 2018

Другой использует GNU awk и 2d массивы для удаления дубликатов в $4:

$ awk '{
    i=$1 OFS $2 OFS $3                        # key to hash
    a[i][$4]                                  # store each $4 to separate element
    c[i]++                                    # count key references
}
END {
    for(i in a) {                             
        k=1                                   # comma counter for output
        printf "%s %s ",c[i],i                # output count and key
        for(j in a[i])                        # each a[]i[j] element
            printf "%s%s",((k++)==1?"":","),j # output commas and elements
        print ""                              # line-ending
    }
}' file

Вывод в случайном порядке по умолчанию:

2 E F G N,P
3 A B C Q,D,J
1 G Y F Q
1 E B C P
2 H F S L

Поскольку мы используем GNU awk, порядок вывода можно легко изменить, установив PROCINFO["sorted_in"]="@ind_str_asc":

3 A B C D,J,Q
1 E B C P
2 E F G N,P
1 G Y F Q
2 H F S L
0 голосов
/ 05 сентября 2018

Проще всего сделать следующее:

awk '{key=$1 OFS $2 OFS $3; a[key]=a[key]","$4; c[key]++}
     END{for(key in a) { print c[key],key,substr(a[key],2) }}' <file>

Если вы не хотите дублирования, вы можете сделать

awk '{ key=$1 OFS $2 OFS $3; c[key]++ }
     !gsub(","$4,","$4,a[key]) {a[key]=a[key]","$4; }
     END{for(key in a) { print c[key],key,substr(a[key],2) }} <file>
...