행의 모든 ​​열이 동일한지 확인하는 스크립트 속도를 높입니다.

행의 모든 ​​열이 동일한지 확인하는 스크립트 속도를 높입니다.

각 행의 모든 ​​"열"이 동일한지 확인한 다음 동일한 요소 중 하나 또는 "no_match"를 포함하는 새 파일을 작성하는 스크립트의 속도를 높여야 합니다. 파일은 쉼표로 구분되며 약 15,000줄로 구성되며 다양한 수의 "열"을 포함합니다.

예를 들어:

1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59

새 파일에 쓰기:

1-69
no_match
1-46
no_match
6-1
5-51
4-59

두 번째 행과 네 번째 행은 서로 다른 열을 포함하고 있으므로 삭제합니다.

다음은 우아한 스크립트와는 거리가 먼 것입니다.

#!/bin/bash

ind=$1 #file in
num=`wc -l "$ind"|cut -d' ' -f1` #number of lines in 'file in'
echo "alleles" > same_alleles.txt #new file to write to

#loop over every line of 'file in'
for (( i =2; i <= "$num"; i++));do
    #take first column of row being looped over (string to check match of other columns with)
    match=`awk "FNR=="$i" {print}" "$ind"|cut -d, -f1`
    #counts how many matches there are in the looped row
    match_num=`awk "FNR=="$i" {print}" "$ind"|grep -o "$match"|wc -l|cut -d' ' -f1`
    #counts number of commas in each looped row
    comma_num=`awk "FNR=="$i" {print}" "$ind"|grep -o ","|wc -l|cut -d' ' -f1`
    #number of columns in each row
    tot_num=$((comma_num + 1))
    #writes one of the identical elements if all contents of row are identical, or writes "no_match" otherwise
    if [ "$tot_num" == "$match_num" ]; then
            echo $match >> same_alleles.txt
    else
            echo "no_match" >> same_alleles.txt
    fi
done

#END

현재 스크립트가 약 15,000개 행을 모두 완료하는 데 약 11분이 소요됩니다. 속도를 높이는 방법을 잘 모르겠습니다(솔직히 작동하게 할 수 있다는 것에 놀랐습니다). 언제든지 취소하면 좋을 것 같습니다. 다음은 사용할 수 있는 100줄의 작은 발췌문입니다.

allele
4-39
1-46,1-46,1-46
4-39
4-4,4-4,4-4,4-4
3-23,3-23,3-23
3-21,3-21
4-34,4-34
3-33
4-4,4-4,4-4
4-59,4-59
3-23,3-23,3-23
1-45
1-46,1-46
3-23,3-23,3-23
4-61
1-8
3-7
4-4
4-59,4-59,4-59
1-18,1-18
3-21,3-21
3-23,3-23,3-23
3-23,3-23,3-23
3-30,3-30-3
4-39,4-39
4-61
2-70
4-38-2,4-38-2
1-69,1-69,1-69,1-69,1-69
1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59
1-18
3-7
1-69
4-30-4
4-39
1-69
1-69
4-39
3-23,3-23,3-23
4-39
2-5
3-30-3
4-59,4-59,4-59
3-21,3-21
4-59,4-59
3-9
4-59,4-59,4-59
4-31,4-31
1-46,1-46
1-46,1-46,1-46
5-51,5-51
3-48
4-31,4-31
3-7
4-61
4-59,4-59,4-59,4-61,4-61,4-61
4-38-2,4-38-2
3-21,3-21
1-69,1-69,1-69
3-23,3-23,3-23
4-59,4-59
3-48
3-48
1-46,1-46
3-23,3-23,3-23
3-30-3,3-30-3
1-46,1-46,1-46
3-64
3-73,3-73
4-4
1-18
3-7
1-46,1-46
1-3
4-61
2-70
4-59,4-59
5-51,5-51
3-49,3-49
4-4,4-4,4-4
4-31,4-31
1-69
1-69,1-69,1-69
4-39
3-21,3-21
3-33
3-9
3-48
4-59,4-59
4-59,4-59
4-39,4-39
3-21,3-21
1-18

내 스크립트는 이 작업을 완료하는 데 약 7초가 걸립니다.

답변1

$ awk -F, '{ for (i=2; i<=NF; ++i) if ($i != $1) { print "no_match"; next } print $1 }' file
1-69
no_match
1-46
no_match
6-1
5-51
4-59

죄송합니다. 귀하의 코드를 보지도 않았습니다. 너무 많은 일이 일어나고 있습니다. 루프 본문에서 동일한 데이터를 세 번 호출 하는 경우 awk이를 보다 효율적으로 수행할 수 있는 다른 방법을 찾아야 합니다. 또한 귀하가 관련되어 있는 경우 해당 작업을 완료 awk할 필요가 없으며 쉽게 완료 할 수 있습니다 grep( 이 경우는 아님).cutawk

위 스크립트는 awk한 번에 하나의 쉼표로 구분된 줄을 읽고 각 필드를 첫 번째 필드와 비교합니다. 테스트가 실패하면 no_match문자열이 인쇄되고 스크립트는 다음 줄에서 계속됩니다. 루프가 완료되면(불일치가 발견되지 않음) 첫 번째 필드가 인쇄됩니다.

스크립트로:

#!/usr/bin/awk -f

BEGIN { FS = "," }

{
    for (i=2; i<=NF; ++i)
        if ($i != $1) {
            print "no_match"
            next
        }

    print $1
}
  • FS-F명령줄의 옵션을 사용하여 설정할 수도 있는 입력 필드 구분 기호입니다 . awk이 문자의 각 줄은 분할되어 필드를 생성합니다.
  • NF현재 레코드의 필드 수("행의 열 수")입니다.
  • $ii변수 또는 상수일 수 있는 현재 레코드의 i:번째 필드를 참조합니다 ( 에서와 같이 $1).

관련된:


마른다양성:

#!/usr/bin/awk -f

BEGIN { FS = "," }

{
    output = $1

    for (i=2; i<=NF; ++i)
        if ($i != output) {
            output = "no_match"
            break
        }

    print output
}

답변2

Awk는 완전한 프로그래밍 언어입니다. 당신은 이미 그것을 사용했습니다. 하지만 회선당 여러 호출이 있는 간단한 작업에만 사용하지 말고 전체 작업에 사용하세요. awk에서는 필드 구분 기호를 사용하고, cut을 사용하지 마십시오. awk에서 처리를 완료합니다.

awk -F',' '
{ 
  eq=1; 
  for (i = 2; i <= NF; i++)
    if ($1 != $i)
      eq=0;
  print eq ? $1 : "no_match";
}
' $1

답변3

perl을 사용하여 List::MoreUtils스칼라 컨텍스트에서 distinct/ 요소를 평가합니다.uniq

perl -MList::MoreUtils=distinct -F, -lne '
  print( (distinct @F) > 1 ? "no_match" : $F[0])
' example 
1-69
no_match
1-46
no_match
6-1
5-51
4-59

답변4

다음과 같이 편집기를 사용하여 이 작업을 수행할 수도 있습니다 sed.

sed -e '
    s/^\([^,]*\)\(,\1\)*$/\1/;t
    s/.*/NOMATCH/
' input.csv

regex여기서 우리는 그 자체를 곱하고 줄의 끝에 도달하는 것에 의존합니다 . 가능하다면 첫 번째 필드로 종료하고, 그렇지 않으면 flash 로 종료하세요 NOMATCH.

설명하다:

이 pbm을 보았을 때 이런 생각이 떠올랐습니다. as
의 다양한 색상을 생각해 보세요 comma-separated fields. stones그들이 첫 번째 돌의 반복으로 앞에 쉼표를 붙여서 줄을 설 수 있다고 상상해 보십시오.

그것은 다음과 같습니다:

STONEA ,STONEA ,STONEA ,STONEA ... all the way to end of line

이제 정규식으로 표현하면 다음과 같습니다.

^ (STONEA) (,\1) (,\1) (,\1) ... all the way to end of line

^ (STONEA) (,\1)* $

산출:

1-69
NOMATCH
1-46
NOMATCH
6-1
5-51
4-59

관련 정보