删除相同的列值

删除相同的列值

我有一个非常大的文件,如果列值为 9,我想删除它。

样本:

我的文件值是这样的:

1 5 8 3 5 9 5 7 6 9
2 5 7 4 2 9 7 6 3 1
5 9 7 4 1 9 5 7 9 1

我想删除所有行上的值为 9 的任何列(我的列大小非常大,所以我无法检查第一列 = 9 第二列 = 9 ...等)。我需要一个动态脚本。

输出应该是这样的:

1 5 8 3 5 5 7 6 9
2 5 7 4 2 7 6 3 1
5 9 7 4 1 5 7 9 1

我是新人,尝试了很多事情但没有做到。

我该怎么做?

感谢您的帮助

答案1

在Python中:

#! /usr/bin/env python3

import sys
# Get the numbers
numbers = [[int(x) for x in line.strip().split()] for line in sys.stdin] 
# Get indexes of 9 in sets for each row
index_9 = (set(x for x, num in enumerate(line) if num == 9) for line in numbers)  

common_column = next(index_9).intersection(*index_9)

for line in numbers:
    print(' '.join((str(num) for x, num in enumerate(line) if x not in common_column)))

答案2

awk方法假设每行具有相同数量的字段...(如问题中给出的示例所示)。它还假设没有空字段。

cat <<EOF >file
1 5 8 3 5 9 5 7 6 9
2 5 7 4 2 9 7 6 3 1
5 9 7 4 1 9 5 7 9 1
EOF

awk '{ for (c=1; c<=NF; c++) a[NR,c]=$c }
 END { for (c=1; c<=NF; c++) { 
         vc="" # values in column
         for (r=1; r<=NR; r++) { 
           vc = vc " " a[r,c]  }
         if ( ! gensub( /[9 ]/,"","g",vc) ) {
           for (r=1; r<=NR; r++) {
             a[r,c] = "" } }
       }
       for (r=1; r<=NR; r++) {
         for (c=1; c<=NF; c++) {
           if ( a[r,c] ) printf a[r,c]" " } 
         print "" }
     }' file

# output
1 5 8 3 5 5 7 6 9 
2 5 7 4 2 7 6 3 1 
5 9 7 4 1 5 7 9 1

答案3

这是使用 bash / GNU coreutils 的可能方法,不需要太多存储:

  1. cut逐列记录文件并记录不完全由 9 组成的任何列的索引;如果你知道你的文件有多少列(在本例中为 10),它可能很简单

    for ((i=1;i<11;i++)); do 
      [[ $(cut -d' ' -f${i} file | sed '/^9$/d' | wc -l) -eq 0 ]] || a+=($i)
    done
    

    (利用这样的事实:删除所有 9 后,只有完全由 9 组成的列的长度为 0);然后

  2. 将要保留的列列表传递给进一步的cut命令,使用 的更改IFS将数组转换为逗号分隔的列表

    (IFS=, ; cut -d' ' -f"${a[*]}" file)
    

如果您的版本cut支持该--complement标志,您可以记录以下列包含全 9 以及cut除以下之外的所有内容:

    for ((i=1;i<11;i++)); do
      [[ $(cut -d' ' -f${i} file | sed '/^9$/d' | wc -l) -eq 0 ]] && a+=($i)
    done

    (IFS=, ; cut -d' ' --complement -f"${a[*]}" file)

答案4

鉴于问题中的信息我目前可以想出:

awk '{for (i=1; i<NF; i++){ a[i]+=$i; b[i]=b[i]" " $i}} END{for (i=1; i<NF; i++) if (a[i]/NR!=9) {printf "%s\n", b[i]}}' same-column-values

该函数遍历文件,将总和计算到变量“a”中,并将该值附加到索引数组“b”中。完全读取文件后,将迭代总和数组,如果总和除以记录数 (NR) 不等于 9,则打印数组“b”中的相应行。

这让我得到一个输出 1 2 5 5 5 9 8 7 7 3 4 4 5 2 1 5 7 5 7 6 7 6 3 9

这样做的缺点是输出应该从上到下读取,并且应该从上到下转换为左到右。

或者,您可以使用以下命令获取仅包含值 9 的列列表:

awk '{for (i=1; i<NF; i++){ a[i]+=$i; b[i]=b[i]" " $i}} END{for (i=1; i<NF; i++) if (a[i]/NR==9){print i; }}' same-column-values

相关内容