在一个逗号分隔的列表中创建对象大小的摘要

在一个逗号分隔的列表中创建对象大小的摘要

我有一个包含两个字段的大文件,第一个字段表示对象名称,第二个字段表示该对象的大小:

A 1
A 2
B 4
ABC 12
C 5
A 9
B 3
ABC 6

我想用以下格式总结该列表:

A 1,2,9
ABC 12,6
B 4,3
C 5

我想出的解决方案是创建文件中存在的对象的唯一列表,迭代它并将其与原始文件匹配

for object in $(awk '{print $1}' objects_with_sizes.txt | sort -u);do
    echo -n "$object "
    awk -v pattern="$object" '$1==pattern{printf "%s%s" ,sep,$2;sep=","} END{print ""}' objects_with_sizes.txt  
done 

此实现需要很长时间才能运行,是否有更有效的方法来创建所需的输出?

答案1

$ awk '{ object[$1]= (object[$1]==""?"":object[$1] ",") $2 }
  END  { for(obj in object) print obj, object[obj] }' infile
A 1,2,9
B 4,3
C 5
ABC 12,6

更有效一点(使用内存;对于无法放入内存的大文件很重要),即不将文件部分缓冲到上面单独使用 awk 命令执行的操作,但仅直到对象键发生更改为止:

$ <infile sort -k1,1 -k2,2n |\
  awk 'pre!=$1 { if(obj) { print obj; obj="" } }
               { obj= (obj==""?$1 " ":obj ",") $2; pre=$1 }
  END{ if(obj) print obj }'
A 1,2,9
ABC 6,12
B 3,4
C 5

答案2

使用 GNU datamash

$ datamash -t ' ' -s -g 1 collapse 2 <file
A 1,2,9
ABC 12,6
B 4,3
C 5

选项:

  • -t '_'使用空格字符作为字段分隔符
  • -s分组前对输入进行排序
  • -g 1第一个字段上的组
  • collapse 2将第二个字段的值折叠到逗号分隔的列表中

答案3

我们可以排序然后输入到 GNU sed,它将当前的第一个字段与前一个字段进行比较,以生成逗号分隔的 OR 打印直到该点。

$ < file sort -s -k1,1 \
| sed -Ee '
  :a
    $!N
    s/^((\S+)\s.*)\n\2\s+(\S+)/\1,\3/
  ta
  P;D
' -
A 1,2,9
ABC 12,6
B 4,3
C 5

相关内容