这是我的数据集:
col1,col2,col3
a,b,c
a,d,f
d,u,v
f,g,h
d,u,g
x,t,k
Run Code Online (Sandbox Code Playgroud)
预期输出:
f,g,h
x,t,k
Run Code Online (Sandbox Code Playgroud)
选择标准:
如果某件事多次发生col1
,则所有关联的行都将被删除。
我可以使用 Linuxsort
或uniq
其他方式解决这个问题吗?
这是一种“非缓冲” (1)两遍方法awk
(仅适用于常规文件)。
awk -F',' 'NR==FNR{cnt[$1]++;next} FNR>1&&cnt[$1]==1' input.csv input.csv
Run Code Online (Sandbox Code Playgroud)
这将处理该文件两次,因此在命令行上将其作为参数声明两次。
-F','
将字段分隔符设置为,
。NR
全局行计数器 等于每个FNR
文件行计数器时,我们记录在数组中遇到第 1 列中的每个值的频率cnt
(将该值作为“数组索引”),但立即跳到下一行处理。awk
规则块之外的表达式的语法,该表达式的计算结果是true
指示awk
打印当前行。(1)作为对评论的回应,我将非缓冲放在引号中,因为由于该解决方案会将文件中的一些数据临时存储在 RAM 中,因此它确实会占用 RAM。然而,除了RAM 中的任何其他滚动保持数据之外,它不会逐字存储文件内容(我认为在实际意义上是“缓冲”)。
假设该文件是/tmp/data
您可以使用 perl 单行代码来完成的:
perl -e 'while(<STDIN>) { /(^\S+?),/; $show->{$1}=$_; $count->{$1}++;}; foreach(keys %$show) {print $show->{$_} if($count->{$_} == 1);}' < /tmp/data
或者更具可读性...:
while(<STDIN>) { #loop through all lines in the input and put the lines in "$_"
/(^\S+?),/; #Everything before the first "," now ends up in "$1"
$show->{$1} = $_; #a hash will be created with as keys the "$1" and as values the "$_"
$count->{$1}++; #In the hash $count the number of occurrences will be increased everytime the same $1 appears
}
foreach(keys %$show) { #loop trough all lines
print $show->{$_} if($count->{$_} == 1); #only print them if they occur once
}
Run Code Online (Sandbox Code Playgroud)
awk
唯一的解决方案
不遵守秩序
awk -F, 'NR>1 { count[$1]++ ; line[$1]=$0 ;}
END { for ( c in count) if (count[c] ==1) print line[c]}' data
Run Code Online (Sandbox Code Playgroud)
维持秩序
awk -F, 'NR>1 { row[a]=$0; col[a]=$1; count[$1]++; ++a; }
END { for (i=0; i<a; ++i) if (count[col[i]]==1) print row[i]; }' data
Run Code Online (Sandbox Code Playgroud)
在哪里
-F,
告诉 awk 用作,
分隔符
NR>1
第一行之后
count[$1]++
计算第一列的元素
line[$1]=$0
商店线
END
文件结束后
for ( c in count)
循环遍历元素
if (count[c] ==1)
如果只有一个
print line[c]
打印行
a
和col[]
用于存储顺序保留变体中的行顺序。
这可以单行,为了可读性我折叠起来