从行中唯一排序

从行中唯一排序

您能给我建议如何从行或行中进行唯一排序吗?我有这样的信息:

Special   c1,c2,c5,c7,c1,c2   
Special2  C6

Special(这是和之间的制表符c1...)。

我想要这样的输出:

Special   c1,c2,c5,c7  
Special2  C6

我怎样才能做到这一点?

答案1

使用这个答案,

perl -MList::MoreUtils=uniq -laF'\t' -ne '
    $F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'

这取决于外部包列表::更多实用工具。如果您不想安装外部依赖项,则重新实现该uniq功能是只需要几行 Perl 代码。 (尽管我似乎已将其作为 macOS 基本系统的一部分进行安装。)

答案2

perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf

解释

  • -F'\t|,'@F=> 将每个记录字段拆分为TAB或字符数组comma
  • -l也会设置RStonewlineORSto newline
  • -a将根据FS选择的内容自动将每个记录拆分为单词-F
  • -n将在输入上设置循环读取的隐式记录,AND仅在要求时才打印内容。
  • -e是根据上面的choenPerl对输入的每条记录执行的代码。RS-l
  • 第一个元素将由 给出shift,其余元素将uniquified通过将它们存储为散列的键来给出,%h每次读入记录时都会重新生成该散列。然后对唯一元素进行排序并用逗号连接并打印。

答案3

使用 OpenBSD awk、GNUawk和进行了测试mawk

awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'

第一个awk将给定数据扩展为

Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6

它使用逗号和多个空格作为字段分隔符,并且对于输入的每个记录(行),它在单独的行上依次打印第一个字段,然后依次打印其他每个字段。这假设除了将被正确解释为分隔符的位置之外,行上没有其他空格或逗号。

中间sort的将其排序为

Special2 C6
Special c1
Special c2
Special c5
Special c7

它使用整行作为排序键进行排序,并丢弃任何重复的行。

最后awk将数据重新组合成

Special c1,c2,c5,c7
Special2 C6

它通过使用第一个字段作为关联数组的键并将相应数据的逗号分隔串联存储在第二个字段中作为值来实现此目的。最后,打印所有收集的数据。

答案4

另一种方式是一行:

while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' ';  echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort

它采用每行的第一列 ( echo $line | awk '{print $1}' | tr '\n' ' ';),并在将其转换为单列后对用“,”分隔的第二列值进行排序,以便应用sort,然后将其转换回具有原始格式的单行 ( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',')。

按照@tripleee的建议进行行分割:

while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort

相关内容