删除unix中完全相同的重复列

kkbh8khc  于 2022-12-18  发布在  Unix
关注(0)|答案(5)|浏览(179)

假设我有一个文件如下:

number 2 6 7 10 number 6 13  
name1 A B C D name1 B E   
name2 A B C D name2 B E  
name3 B A D A name3 A F  
name4 B A D A name4 A F

我希望删除完全相同的重复列,输出文件如下所示:

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F

我用sortuniq命令行,但从来不知道如何做的列。谁能建议一个好方法?

xam8gpfp

xam8gpfp1#

下面是使用awk时保持顺序的一种方法

awk 'NR==1{for(i=1;i<=NF;i++)b[$i]++&&a[i]}{for(i in a)$i="";gsub(" +"," ")}1' file

输出

number 2 6 7 10 13  
name1 A B C D E   
name2 A B C D E  
name3 B A D A F  
name4 B A D A F

工作原理

NR==1


如果是第一条记录

for(i=1;i<=NF;i++)

字段上的循环,NF是字段数

b[$i]++&&a[i]

如果$i(包含在字段i中的数据)出现了不止一次,则向数组a添加一个键为i的元素。
对所有记录(包括记录1)执行下一个块。

{for(i in a)$i="";

对于中的每个键,将相应的字段设置为空。

gsub(" +"," ")

删除多余空格
计算结果始终为true,因此打印所有记录。

vxf3dgd4

vxf3dgd42#

下面的Perl一行程序就可以做到这一点:

perl -an -e '@cols = grep { !$seen{$F[$_]}++ } 0..$#F unless @cols; print join " ", @F[@cols],"\n"' inputfile

-ainputfile的每一行拆分为@F。文件的第一行用于从左到右构建列索引列表,只保留那些看不见的列。接下来,它打印@F的切片,其中每行只包含这些列。

djmepvbi

djmepvbi3#

您可以使用awk:

NR == 1 {
  for (ii = 1; ii <= NF; ii++) {
    cols[$ii] = ii
  }
  for (ii in cols) {
    printf "%s ", ii
  }
  print ""
}

NR > 1 {
  for (ii in cols) {
    printf "%s ", $cols[ii]
  }
  print ""
}

上面的操作可能会对列进行重新排序,但如果必要的话,可以多做一些工作来修复这个问题。

ahy6op9u

ahy6op9u4#

只需一个awk命令即可删除重复行:

awk '!a[$0]++'

它跟踪一条线出现的次数,一旦一条线出现,a[this row]等于1,所以当它再次出现时,a[this row]已经是True,并且!否定条件,所以它不被打印。
在您的例子中,您希望删除重复的列,但是创建一个函数transpose来将行转换为列,反之亦然。
我在回答Using bash to sort data horizontally时已经这样做了:

transpose () {
  awk '{for (i=1; i<=NF; i++) a[i,NR]=$i; max=(max<NF?NF:max)}
        END {for (i=1; i<=max; i++)
              {for (j=1; j<=NR; j++) 
                  printf "%s%s", a[i,j], (j<NR?OFS:ORS)
              }
        }'
}

然后,它变得微不足道:

$ cat file | transpose | awk '!a[$0]++' | transpose
number 2 6 7 10 13
name1 A B C D E
name2 A B C D E
name3 B A D A F
name4 B A D A F

k2arahey

k2arahey5#

下面是一种完全适用于python3的保序方法

$ cat remove_duplicate_fields.py
import csv
import sys
reader = csv.reader(sys.stdin, delimiter=' ')
columns = []
for row in reader:
    for i, col in enumerate(row):
        if i >= len(columns):
        columns.append([col])
            else:
            columns[i].append(col)
seen_columns = set()
unique_columns = []
matrix_transpose = [list(i) for i in zip(*columns)]
for col in zip(*matrix_transpose):
    if col not in seen_columns:
       seen_columns.add(col)
       unique_columns.append(col)
for column in zip(*unique_columns):
    print(' '.join(column))

它给出所需的结果:

$ echo $'number 2 6 7 10 number 6 13\nname1 A 1 C D name1 B E\nname2 A B C D name2 B E\nname3 B A D A name3 A F\nname4 B A D A name4 A F'
number 2 6 7 10 number 6 13
name1 A B C D name1 B E
name2 A B C D name2 B E
name3 B A D A name3 A F
name4 B A D A name4 A F

$ echo $'number 2 6 7 10 number 6 13\nname1 A B C D name1 B E\nname2 A B C D name2 B E\nname3 B A D A name3 A F\nname4 B A D A name4 A F' | python3 remove_duplicate_fields.py
number 2 6 7 10 13
name1 A B C D E
name2 A B C D E
name3 B A D A F
name4 B A D A F

此外,当将输入的第二行中的第三个字段的值更改为1时,它也给出了正确的结果,因为它没有删除该列,这是因为第3列现在与第7列不同。

$ echo $'number 2 6 7 10 number 6 13\nname1 A 1 C D name1 B E\nname2 A B C D name2 B E\nname3 B A D A name3 A F\nname4 B A D A name4 A F' | python3 remove_duplicate_fields.py
number 2 6 7 10 6 13
name1 A 1 C D B E
name2 A B C D B E
name3 B A D A A F
name4 B A D A A F

相关问题