选择性地转换一个大的CSV



我正在tty Linux上处理一些巨大的CSV文件(>500 MB(。我的数据格式如下:

A, XYZ
A, ZSY
A, TVT
B,  GHJ
B, XYZ
C,  XYZ
C, TVT

输出应如下所示。

A, XYZ, ZSY, TVT
B, GHJ, XYZ, nil
C, XYZ, TVT, nil

第一列充当键,并将所有其他相应的行转换为列。我只有标准的Unix工具(+perl(。

有什么标准的Unix解决方案可以务实地解决这个问题吗?

如果您不关心输出的顺序应该与Input_file相同,那么下面的内容可能会对您有所帮助。

awk 'BEGIN{FS=", ";OFS=","}{a[$1]=a[$1]?a[$1] OFS $NF:$NF} END{for(i in a){print i,a[i]}}' Input_file

OR

awk '
BEGIN{  FS=", ";OFS=","  }
{
a[$1]=a[$1]?a[$1] OFS $NF:$NF
}
END{
for(i in a){ print i,a[i] }
}' Input_file

第二个解决方案:如果您希望输出顺序与Input_file的顺序相同,那么以下内容可能会对您有所帮助。

awk '
BEGIN   { FS=", ";OFS="," }
!b[$1]++{ c[++count]=$1   }
{
a[$1]=a[$1]?a[$1] OFS $NF:$NF
}
END{
for(i=1;i<=count;i++){  print c[i],a[c[i]]  }
}'  Input_file

这是awk的另一个解决方案,取决于您的数据是否为第一列排序

排序:

awk -F',' -v OFS=',' '{if(a!=$1){printf (a!="")?"n"$1:$1;a=$1} printf "%s%s",OFS,$2}END{print}'

简要说明,

  1. if(a!=$1){printf (a!="")?"n"$1:$1;a=$1}:已定义的a,如果未定义则打印
  2. printf "%s%s",OFS,$2:始终打印以下列

未分拣

sort -sk1,1 file | awk -F',' -v OFS=',' '{if(a!=$1){printf (a!="")?"n"$1:$1;a=$1} printf "%s%s",OFS,$2}END{print}'

使用sort -sk1,1对第一列进行排序,然后执行与排序列相同的操作。

这只需在找到每个唯一密钥时打印其值,这样您就不必将整个巨大的文件存储在内存中:

$ cat tst.awk
BEGIN {
FS  = "[[:space:]]*,[[:space:]]*"
OFS = ", "
}
$1 != prev {
if ( NR > 1 ) {
prt()
}
prev = $1
}
{
vals[++numVals] = $2
}
END {
prt()
}
function prt(   numCols, colNr, val) {
numCols = 3
printf "%s", prev
for (colNr=1; colNr<=numCols; colNr++) {
val = (colNr in vals ? vals[colNr] : "nil")
printf "%s%s", OFS, val
}
print ""
delete vals
numVals = 0
}
$ awk -f tst.awk file
A, XYZ, ZSY, TVT
B, GHJ, XYZ, nil
C, XYZ, TVT, nil

最新更新