根据另一列的值删除重复项

Han*_*otc 9 sed awk text-processing

我有以下文件:

AA,true
AA,false
BB,false
CC,false
BB,true
DD,true
Run Code Online (Sandbox Code Playgroud)

我正在尝试查找重复项并删除列值等于true.

作为输出它应该是:

AA,false
BB,false
CC,false
DD,true
Run Code Online (Sandbox Code Playgroud)

Wil*_*ard 14

简单版:

sort input.txt | awk -F, '!a[$1]++'
Run Code Online (Sandbox Code Playgroud)

“false”在“true”之前按字母顺序排序,这里的 awk 命令只为每个不同的第一个字段值保留第一行。

如果要保留“真”而不是“假”,请对其进行反向排序,将其传递给相同的 Awk 命令,然后再次反向排序。

  • @Sundeep 为什么使用两个 `sort` 调用?为什么不只是`sort -ut, -k1,1 input.txt`? (2认同)
  • @terdon 因为`-u` 将保留从输入文件中找到的第一行重复项...对于给定的情况,输入必须在应用`-u` 之前进行排序...例如:`AA,true` 将被打印而不是 `AA,false`,因为它首先出现在给定的样本中......同样的原因为什么 `awk -F, '!a[$1]++'` 单独不能解决这个问题 (2认同)

Dop*_*oti 9

awk -F, '$2 == "false" {data[$1]=$2 } $2=="true" { if ( data[$1]!="false" ) { data[$1]=$2 } } END { OFS=","; for (item in data) { print item,data[item] }}' input
Run Code Online (Sandbox Code Playgroud)

要垂直展开脚本以进行说明:

BEGIN {
   FS=","         # Set the input separator; this is what -F, does.
}
$2 == "false" {    # For any line whose second field is "false", we
   data[$1]=$2     # will use that value no matter what.
}
$2=="true" {                    # For lines whose second field is "true",
   if ( data[$1]!="false" ) {   # only keep if if we haven't yet seen a
      data[$1]=$2               # "false"
   }
}
END {                           # Now that we have tabulated our data, we
   OFS=","                      # can print it out by iterating through 
   for (item in data) {         # the array we created.
      print item,data[item]
   }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

perl -F, -lane '
   exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
   $h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
   END{ print for @h; }
' duplicates.file
Run Code Online (Sandbox Code Playgroud)

数据结构:

  • 哈希%h的键是第一个字段(AAA、BBB、CCC 等),对应的值是表示遇到键的顺序的数字。因此,例如,密钥 AAA => 0,密钥 BBB => 1,密钥 CCC => 2。
  • @h元素为按打印顺序包含的行的数组。因此,如果在数据中同时发现 true 和 false,那么 false 值将进入数组。OTW,如果有一种类型的数据,那么就会存在。

另一种方法是使用 GNU sed:

sed -Ee '
   G
   /^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
   /^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
   /^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
      s//\3\1\2\5/;h;ba
   }
   s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
   h;:a;$!d;g
' duplicates.file
Run Code Online (Sandbox Code Playgroud)

FWIW,下面列出了上述 GNU-sed 代码的 POSIX 等效代码:

sed -e '
   G

   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
   /^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba

   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
   /^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba

   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
      s//\3\1\2/
      h
      ba
   }
   /^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
      s//\3\1\2\n/
      h
      ba
   }

   y/\n_/_\n/
   s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
   y/\n_/_\n/

   h;:a;$!d;g
' duplicates.file
Run Code Online (Sandbox Code Playgroud)

解释

  • 在这个方法中,我们将最终要打印的结果存储在保持空间中。
  • 对于每行读取,我们将保持空间附加到模式空间,以检查当前行与保持空间的现有状态。
  • 现在,在此比较过程中可能会发生 5 件事:
    • a) 当前行匹配保持行中的某处 & false:false。
      • [ACTION] 由于发现相同的错误状态,所以什么都不做。
    • b) 当前行匹配保持行中的某处 & true:true。
      • [ACTION] 由于找到了相同的真实状态,所以什么都不做。
    • c) 当前行匹配保持行中的某处 & true:false。
      • [ACTION] 由于错误状态已经存在,所以什么都不做。
    • d) 当前行匹配保持行中的某处 & false:true。
      • [ACTION] 这涉及到一些工作,因为我们需要在 true 所在的完全相同的位置替换 false 线。
    • e) 当前行不匹配保持行中的任何位置。
      • [ACTION] 将当前行移到最后。

结果

AA,false
BB,false
CC,false
DD,true
Run Code Online (Sandbox Code Playgroud)