매우 큰 파일이 있는데 열 값이 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
파이썬에서는:
#! /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