保留每列的唯一值(以逗号分隔)

df_*_*f_v 5 text-processing deduplication

我在 Linux 系统上有一个.tsv(制表符分隔的列)文件,其中包含以下列,其中包含以逗号分隔的不同类型的值(字符串、数字):

col1    col2    
.       NS,NS,NS,true,true      
.       12,12,12,13 
1,1,1,2 door,door,1,1   
Run Code Online (Sandbox Code Playgroud)

我想保留独特的价值观(不幸的是我尝试过但不能)。这将是输出:

col1 col2   
.    NS,true        
.    12,13  
1,2  door,1 
Run Code Online (Sandbox Code Playgroud)

ste*_*ver 7

这是一个 Miller 变体,它将值字符串拆分为整数索引映射,然后通过交换映射的键和值(将键连接逗号分隔的字符串)来唯一化它:

mlr --tsv put 'for (k,v in $*) {
  $[k] =  joink(apply(splitnvx(v,","), func(k,v) {return{v:k}}),",")
}' file.tsv
Run Code Online (Sandbox Code Playgroud)

或者,在 perl5 中,在List::Util模块的帮助下:

perl -MList::Util=uniq -F'\t' -lpe '
  $_ = join "\t", map { join ",", uniq split /,/, $_ } @F
' file.tsv
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 6

使用Miller ( mlr) 循环每个输入记录中的制表符分隔字段,用逗号分割字段的值,将每个生成的字符串添加为名为 的映射中的键,最后通过使用逗号seen连接映射中的键来重写字段seen作为分隔符:

$ mlr --tsv put 'for (k,v in $*) { seen={}; for (i in splitax(v,",")) { seen[i]=1 } $[k] = joink(seen,",") }' file
col1    col2
.       NS,true
.       12,13
1,2     door,1
Run Code Online (Sandbox Code Playgroud)

米勒的put表达式印得很漂亮:

for (k, v in $*) {
    seen = {};
    for (i in splitax(v, ",")) {
        seen[i] = 1
    }
    $[k] = joink(seen, ",")
}
Run Code Online (Sandbox Code Playgroud)

将分割值添加为映射中的键可以对它们进行重复删除。该splitax()函数将分隔符上的字符串拆分为数组,而不推断每个生成项的类型(它们将是字符串)。该joink()函数将映射的键连接在一起形成由给定分隔符分隔的字符串。k外循环中的和的值v分别是字段名称及其值。


jub*_*us1 4

使用Raku(以前称为 Perl_6)

~$ raku -ne '.split("\t")  \
                .map: *.split(",").unique.join(",") andthen  \
             .join("\t").put;'   file
Run Code Online (Sandbox Code Playgroud)

-ne使用逐行非自动打印 ( ) 命令行标志。从文件开始TSV,您可以split使用制表符,然后map进入每个结果元素,然后再次split使用逗号。这里 Raku 的unique例程将删除重复项(join此时您再次返回逗号)。

Raku 语言的一个很好的功能是我所说的 “连接器”代码短语,例如andthen,可以简单地将其视为将左侧的返回值重新加载到$_右侧的主题变量中。在 RHS 上,列join在选项卡上重新组合在一起,然后再输出put

输入示例:

col1    col2    
.   NS,NS,NS,true,true  
.   12,12,12,13 
1,1,1,2 door,door,1,1   
Run Code Online (Sandbox Code Playgroud)

示例输出:

col1    col2    
.   NS,true 
.   12,13   
1,2 door,1
Run Code Online (Sandbox Code Playgroud)

注意:Raku 的unique例程采用as命名参数(在 Raku 行话中也称为“副词”)。因此,如果您想比较字符串,您可以编写.unique(as => *.fc)基于“foldcase”的比较(即不区分大小写的字符串比较)。

https://docs.raku.org/routine/unique
https://docs.raku.org/type/Cool#routine_fc
https://docs.raku.org
https://raku.org

  • @terdon如果你不介意用 List::Util 作弊,你可以做 `perl -MList::Util=uniq -F'\t' -pe '$_ = join "\t", map { join "," , uniq split /,/, $_ } @F' file.tsv` (2认同)