【问题标题】:Delete and combine rows in CSV file for special condition on columns [closed]删除并合并 CSV 文件中的行以获取列上的特殊条件 [关闭]
【发布时间】:2021-06-27 21:46:27
【问题描述】:

我在 csv 文件中有以下内容:

ID Contact_id Tags_id
"id114" "" "Tags_id3"
"id12" "" "Tags_id1"
"" "" "Tags_id3"
"id3353" "contact_id8764" "Tags_id5"
"id355" "contact_id16" "Tags_id6"
"" "" "Tags_id7"
"" "" "Tags_id3"
"" "contact_id564" "Tags_id2"
"" "" "Tags_id12"
"id12076" "contact_id137" "Tags_id7"
"" "" "Tags_id3"
"" "" "Tags_id5"
"" "" "Tags_id1"
... ... ...

用于测试的纯文本:

ID,Contact_id,Tags_id
"id114","","Tags_id3"
"id12","","Tags_id1"
"","","Tags_id3"
"id3353","contact_id8764","Tags_id5"
"id355","contact_id16","Tags_id6"
"","","Tags_id7"
"","","Tags_id3"
"","contact_id564","Tags_id2"
"","","Tags_id12"
"id12076","contact_id137","Tags_id7"
"","","Tags_id3"
"","","Tags_id5"
"","","Tags_id1"

预期结果:

Contact_id Tags_id
"contact_id8764" "Tags_id5"
"contact_id16" "Tags_id6,Tags_id7,Tags_id3,Tags_id2,Tags_id12"
"contact_id564" "Tags_id6,Tags_id7,Tags_id3,Tags_id2,Tags_id12"
"contact_id137" "Tags_id7,Tags_id3,Tags_id5,Tags_id1"
... ...

纯文本的预期结果:

Contact_id,Tags_id
"contact_id8764","Tags_id5"
"contact_id16","Tags_id6,Tags_id7,Tags_id3,Tags_id2,Tags_id12"
"contact_id564","Tags_id6,Tags_id7,Tags_id3,Tags_id2,Tags_id12"
"contact_id137","Tags_id7,Tags_id3,Tags_id5,Tags_id1"
  • 首先删除所有具有 ID 且没有 Contact_id 的行(如具有 id114 的行)。
  • 在下一个 ID (id3353) 之前,删除 ID 下的所有行和没有 Contact_id(如 id12 下的行)。
  • 第三,如果 ID 和 Contact_id 可用,则收集下面的标签,直到具有 Contact_id 的行中的下一个 ID。为ID下的所有Contact_id添加相同的Tags集合(Contact_id16和Contact_id564具有相同的Tags,属于id355。
  • 第四删除ID列

我用 vim 宏尝试过,但没有任何成功。我知道 awk 可能更适合这项任务,但我仍在学习它,也无法做到。也许还有另一种方法可以解决此任务。我希望有人可以提供帮助。

【问题讨论】:

  • 请以纯文本格式发布您的输入数据样本,以便轻松复制/粘贴以进行脚本测试。
  • @karakfa 你是对的,对不起。我会保留表格以便更好地理解。

标签: csv awk vim


【解决方案1】:

下面的可能很丑,但是试试这个。

awk -F ',' -f foo.awk input.txt

foo.awk

NR == 1          { print $2, $3; next }
                 { gsub(/\042/, "", $0) } # remove double quotes
$1 && ($1 != id) { flush(); id = $2 ? $1 : "" } # when ID is changed, print out the 'buffer'.
!id              { next } # note that we defined ID without contact_ID as "" in the previous line.
$2               { cids[i++] = $2 } # add contact_ID if detected
                 { tags = tags "," $3 } # add tag
END              { flush() }

function flush() {
  for (ind in cids) { print "\"" cids[ind] "\",\"" substr(tags, 2) "\"" }
  delete cids; tags = ""; i = 0 # wipe out the buffer
  }

【讨论】:

    【解决方案2】:

    另一种选择

    $ awk -F, 'BEGIN         {e="\"\""; OFS=FS} 
               NR==1         {print $2,$3; next} 
               $1!=e && $2!=e{s=1; id=$1; c=$2; idc[id]=c; idt[id]=$3; next} 
               s && $2!=e    {idc[id]=idc[id] FS $2} 
               s && $3!=e    {idt[id]=idt[id] FS $3} 
               END           {for(id in idc)
                                {n=split(idc[id],cs); 
                                 for(i=1;i<=n;i++) print cs[i], idt[id]}}' file
    
    Contact_id,Tags_id
    "contact_id16","Tags_id6","Tags_id7","Tags_id3","Tags_id2","Tags_id12"
    "contact_id564","Tags_id6","Tags_id7","Tags_id3","Tags_id2","Tags_id12"
    "contact_id8764","Tags_id5"
    "contact_id137","Tags_id7","Tags_id3","Tags_id5","Tags_id1"
    

    使用这种方法不会保留联系人的顺序,如果重要,还需要一些额外的簿记。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-13
      • 2018-03-12
      • 2019-01-09
      • 2012-12-06
      • 2016-11-21
      • 2014-01-29
      • 1970-01-01
      相关资源
      最近更新 更多