从文本文件中删除每个单独列中的重复项



我有一个7列的文本文件,用制表符分隔。每一列都有不同数量的行,其中的值可以重复。我想删除重复项,以便每个列对于特定列只有唯一的值。例如:

输入

C1  C2  C3  C4  C5  C6  C7
111 111 222 333 111 222 777 
222 111 333 333 222 333 666
222 111 444 111 333 555 555
333 444 555 222 444 666 444
444 666 555 777 555 666 333
444 777 777 555 666 888 333
777 888 999 666 888                 
999

输出
C1  C2  C3  C4  C5  C6  C7
111 111 222 333 111 222 777
222 444 333 111 222 333 666
333 666 444 222 333 555 555
444 777 555 777 444 666 444
777 888 777 555 555 888 333
999     999 666 666 
888

我想我需要使用awk来打印每一列,并分别使用sort -u,然后将这些输出粘贴在一起。那么,有没有一种方法可以创建一个循环,在文本文件中有i列,将打印每列| sort - u,然后将它们粘贴在一起?

提前感谢,卡洛斯

使用perl来代替它对真正多维数组的支持:

perl -lane '
for my $n (0..$#F) {
if (!exists ${$vals[$n]}{$F[$n]}) {
push @{$cols[$n]}, $F[$n];
${$vals[$n]}{$F[$n]} = 1;
}
}
END {
for (1..$.) {
my @row;
for my $n (0..$#cols) {
push @row, shift @{$cols[$n]};
}
print join("t", @row);
}
}' input.txt

在任何Unix系统的任何shell中使用任何awk:

$ cat tst.awk
BEGIN { FS=OFS="t" }
{
for (colNr=1; colNr<=NF; colNr++) {
val = $colNr
if ( !seen[colNr,val]++ ) {
rowNr = ++colRowNrs[colNr]
vals[rowNr,colNr] = val
numRows = (rowNr > numRows ? rowNr : numRows)
}
}
numCols = (NF > numCols ? NF : numCols)
}
END {
for (rowNr=1; rowNr<=numRows; rowNr++) {
for (colNr=1; colNr<=numCols; colNr++) {
val = vals[rowNr,colNr]
printf "%s%s", val, (colNr<numCols ? OFS : ORS)
}
}
}

$ awk -f tst.awk file
C1      C2      C3      C4      C5      C6      C7
111     111     222     333     111     222     777
222     444     333     111     222     333     666
333     666     444     222     333     555     555
444     777     555     777     444     666     444
777     888     777     555     555     888     333
999             999     666     666
888

假设

  • 整个输出结果的(awk)数组将适合内存
  • 可变列数和行数

一个想法是由一个(稀疏的)二维值数组组成,其中数组结构看起来像:

values[<column#>][<row#>]=<unique_cell_value>

使用单个awk调用的一个想法是:a)需要通过输入文件进行一次传递,而b)不需要任何转置/粘贴(以防有人认真对待Cyrus的评论/建议):

awk '
BEGIN  { FS=OFS="t" }
{ maxNF = (NF > maxNF ? NF : maxNF)            # keep track of max number of columns
for (i=1; i<=NF; i++) {
if ( $i == "" )                          # ignore empty cell
continue
for (j=1; j<=ndx[i]; j++) {              # loop through values already seen for this column
if ( $i == vals[i][j] ) {            # and if already seen then
$i = ""                           # clear the current cell and
break                             # break out of this for/testing loop
}
}
if ( $i != "" ) {                        # if we got this var and the cell is not empty then 
vals[i][++ndx[i]] = $i                # store the new value in our array
}
}
}
END    { for (j=1; j<=NR; j++) {                      # loop through all possible rows
pfx = ""
for (i=1; i<=maxNF; i++) {               # loop through all possible columns
printf "%s%s", pfx, vals[i][j]       # non-existent array entries default to ""
pfx = OFS
}
printf "n"
}
}
' input_file

注意:数组的数组结构(arr[i][j])需要GNU awk,否则我们可以转换成arr[i,j]的伪双索引数组结构

由此产生:

C1      C2      C3      C4      C5      C6      C7
111     111     222     333     111     222     777
222     444     333     111     222     333     666
333     666     444     222     333     555     555
444     777     555     777     444     666     444
777     888     777     555     555     888     333
999             999     666     666
888

最新更新