我有一个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