我有一个非常大的文件,如果列值为 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 的可能方法,不需要太多存储:
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);然后
将要保留的列列表传递给进一步的
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