将多行汇总为单行

将多行汇总为单行

如何将 csv 文件中的多行汇总为 1 行?我尝试过在 SQL 中执行查询并且它有效,但我不确定如何在 Linux 中实现相同的效果。

这是我当前文件的样子:

swainb02,Ben Swain,1015
swainb02,Ben Swain,1016
swainb02,Ben Swain,1018
swainb02,Ben Swain,1020
shaiks21,Sarah Shaikh,0073
shaiks21,Sarah Shaikh,0080
shaiks21,Sarah Shaikh,0082

有多个用户可以访问多个区号。我正在寻找的是该文件的更简单版本,以提高可读性。

期望的输出:

swainb02,Ben Swain,1015,1016,1018,1020
shaiks21,Sarah Shaikh,0073,0080,0082

知道如何解决这个问题吗?谢谢

答案1

假设您的输入按问题中所示的键值进行分组(如果不只是先对输入进行排序),那么无论您的输入文件有多大,在每个 Unix 机器上的任何 shell 中使用任何 awk 并且几乎不使用内存:

$ cat tst.awk
BEGIN { FS=OFS="," }
{ curr = $1 OFS $2 }
curr != prev {
    printf "%s%s", ors, curr
    prev = curr
    ors = ORS
}
{ printf "%s%s", OFS, $3 }
END { printf ors }

$ awk -f tst.awk file
swainb02,Ben Swain,1015,1016,1018,1020
shaiks21,Sarah Shaikh,0073,0080,0082

答案2

awk对您的结果运行一个小脚本:

awk -F, '
$1$2 != Last    {printf DL "%s", $0
                 Last=$1$2
                 DL=ORS
                 next
                }
                {printf ",%s", $3
                }
END             {print ""
                }
' file
swainb02,Ben Swain,1015,1016,1018,1020
shaiks21,Sarah Shaikh,0073,0080,0082

它打印一次新用户的数据,然后附加区号,直到遇到下一个用户。

答案3

假设输入是简单的 CSV,没有嵌入逗号、换行符或引号,我们可以使用 GNUdatamash按前两个逗号分隔字段进行分组并折叠第三个字段:

$ datamash -t, groupby 1,2 collapse 3 <file
swainb02,Ben Swain,1015,1016,1018,1020
shaiks21,Sarah Shaikh,0073,0080,0082

这假设数据在前两个字段上排序(或者一起排序的记录在文件中彼此相邻,如示例数据中所示)。如果不是,则sort -t, -k 1,2首先传递数据,或datamash与其-s(或--sort) 选项一起使用。


对于通用 CSV 输入,请使用支持 CSV 的工具,例如 Miller ( mlr)。下面执行与上面相同的操作:

$ mlr --csv -N nest --ivar comma -f 3 file
swainb02,Ben Swain,"1015,1016,1018,1020"
shaiks21,Sarah Shaikh,"0073,0080,0082"

请注意,由于mlr它支持 CSV,因此它正确引用了组合的第三个字段及其嵌入的逗号。

答案4

无论行的顺序如何,此 awk 版本都可以工作:

{
  if ($1 "," $2 in a) {
    a[$1 "," $2] = a[$1 "," $2] "," $3
  } else {
    a[$1 "," $2] = $3
  }
}

END {
  for (i in a) {
    print i, a[i]
  }
}

另一方面,csvkit 输出更正确的结果:

csvsql -H -d ',' --query 'SELECT a,b, GROUP_CONCAT(c) as c FROM data GROUP BY a, b' data.txt
a,b,c
shaiks21,Sarah Shaikh,"73.0,80.0,82.0"
swainb02,Ben Swain,"1015.0,1016.0,1018.0,1020.0"

尽管没有引号看起来更好,但另一个示例很容易导致每行的字段数量不同。为了进一步处理,非常需要具有界定的第三字段的输出。

相关内容