【问题标题】:Selectively transposing a large CSV有选择地转置大型 CSV
【发布时间】:2018-12-20 03:44:00
【问题描述】:

我正在 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 解决方案可以实用地解决这个问题?

【问题讨论】:

  • 始终尝试在代码标签中展示您为解决问题所做的努力。
  • 非常感谢您的回答!在删除它之前,我试图在 tty 上编写一个巨大的 bash 脚本。下次一定会发布我的努力!
  • 请显示您目前尝试过的代码。

标签: bash perl csv awk sed


【解决方案1】:

如果您不关心输出的顺序应该与 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

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

【讨论】:

    【解决方案2】:

    这是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,并将其与 sort 本身一起使用。
    • 感谢@RavinderSingh13,已修改。
    • 非常感谢您的回答!!下次我会确保先发布我尝试过的内容!
    • 永远不要使用printf $N,而是始终使用printf "%s", $N。考虑$N 包含像%s 这样的 printf 格式化字符时的区别。 END{print} 所做的是 POSIX 未定义的,因此在某些 awks 中它会打印读取的最后一条记录,在另一些中它会打印一个空字符串,而在另一些中它可以做任何其他事情。最后 - 该脚本无法产生所需的输出,试试吧。
    【解决方案3】:

    这只是在找到每个唯一键时打印它的值,因此您不必将整个大文件存储在内存中:

    $ 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-25
      • 2021-10-26
      相关资源
      最近更新 更多