【问题标题】:csv remove all rows with duplicate values in one columncsv删除一列中具有重复值的所有行
【发布时间】:2017-03-06 01:25:01
【问题描述】:

example1.csv

id1, value1
id2, value2
id3, value3
id1, value4

example2.csv

"06e04,0428","405872,8637110"
"06e04,0428","405872,8637111"
"06e04,0429","405872,8637110"
"06e04,0430","405872,8637110"
"06e04,0431","405872,8637111"

需要删除column1中重复值的行,输出如下

所需输出

example1_out.csv

id2, value2
id3, value3

example2_out.csv

"06e04,0429","405872,8637110"
"06e04,0430","405872,8637110"
"06e04,0431","405872,8637111"

有一些解决方案可以删除保留重复记录之一的重复记录,如此 SO question。但是在这种情况下,column1 具有重复值的所有行都需要从输出中排除。

【问题讨论】:

  • 您已标记您的问题shell。你的意思是bash
  • @Grzesiek - 你能添加 nodejs 答案吗?
  • @user3206440 对不起 使用awk的选择解决方案更短。
  • @ghoti - 是的,我的意思是 bash。

标签: linux shell csv


【解决方案1】:

这个awk 可以在一个命令中做到这一点:

awk -F, '{arr[$1]=$0} seen[$1]++{delete arr[$1]} END{for (i in arr) print arr[i]}' file.csv

id2, value2
id3, value3

对于您编辑的问题,请使用:

awk -F'","' '{arr[$1]=$0} seen[$1]++{delete arr[$1]} END{for (i in arr) print arr[i]}' file.csv

"06e04,0429","405872,8637110"
"06e04,0430","405872,8637110"
"06e04,0431","405872,8637111"

【讨论】:

  • 请注意,这不会保留行顺序id3, value3 id2, value2
  • 当第 1 列的值为 , 时,这不起作用 - 请参阅更新的问题。
  • 我已根据您编辑的问题修改了我的答案。检查给出预期输出的更新答案。
【解决方案2】:
cut -f1 -d, somecsv.csv | sort | uniq -u | grep -Ff- somecsv.csv

第一个命令从输入中提取第一列。第二个命令对 id 进行排序,因此下一个命令只能列出唯一的。最后的 grep 获取唯一的 id 并在输入文件中搜索它们。

【讨论】:

  • 嗯...这也将匹配行,其中 col1 中的文本包含在其他列中...例如id1, valid2
  • 所以将grep -Ff- 更改为sed 's/^/^/' | grep -f-。同样,如果第一列包含特殊字符,它可能会中断...
【解决方案3】:

这是一个较短的 awk 选项。

awk -F, 'NR==FNR{a[$1]++;next} a[$1]<2' file.csv file.csv

这会读取文件两次——一次填充第一个字段的计数器数组,第二次打印计数小于 2 的行。

如果您希望在纯 shell 而不是 awk 中执行此操作,并且您的 shell 是 bash,您可以通过以下方式获得类似的功能:

$ declare -A a=()
$ while IFS=, read f _; do ((a[$f]++)); done < file.csv
$ declare -p a
declare -A a=([id1]="2" [id3]="1" [id2]="1" )
$ while IFS=, read f1 f2; do [ "${a[$f1]}" -lt 2 ] && printf '%s,%s\n' "$f1" "$f2"; done < file.csv
id2, value2
id3, value3

同样,这是两个步骤 - 第一个填充一个计数器数组,第二个是单步执行文件并打印适当的行。

【讨论】:

    【解决方案4】:

    你可以使用awk

    awk -F  "," '{
        if (length(arr[$1]) == 0){
            arr[$1]=$0
            order[i++]=$1
        }
        else{
            delete arr[$1]
        }
    }
     END { 
        for (i = 1; i < length(order); i++) { 
            print arr[order[i]]
        } 
    }' somecsv.csv
    

    它将所有条目存储在一个数组中,如果找到两次,则将其删除。订单通过额外的order 数组保留

    【讨论】:

      猜你喜欢
      • 2022-11-21
      • 2019-11-14
      • 2020-11-15
      • 2016-06-01
      • 2019-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-17
      相关资源
      最近更新 更多