한 필드를 기준으로 고유한 행을 정렬하고 다른 필드를 기준으로 출력할 행을 결정합니다.

한 필드를 기준으로 고유한 행을 정렬하고 다른 필드를 기준으로 출력할 행을 결정합니다.

이것은 문제에 대한 우아한 해결책을 찾는 것에 관한 것이며 저는 효과가 있는 해결책을 가지고 있다고 생각합니다. 내 Ubuntu 컴퓨터에는 다음과 같은 입력 파일 형식(탭으로 구분)이 있습니다.

AC003665.1  17  47813266    AGCAGGCGCA  83
RIOK3   18  23453502    GCAAGGCCCC  52
UBE2Z   17  48910880    CTAAGGATCC  48
CSNK1D  17  82251379    AATTTAGCCA  68
CSNK1D  17  82251379    AATTTCTTGT  38
SMURF1  7   99143726    GACAGATTGG  74
SMURF1  7   99143726    GACAGATTGG  61
RIOK3   18  23453502    GCAAGACTTT  69

필드 3이 발생할 때마다 하나의 행, 즉 필드 5에서 가장 높은 값을 갖는 행을 가져오고 싶습니다. 따라서 출력은 다음과 같아야 합니다.

AC003665.1  17  47813266    AGCAGGCGCA  83
CSNK1D  17  82251379    AATTTAGCCA  68
UBE2Z   17  48910880    CTAAGGATCC  48
SMURF1  7   99143726    GACAGATTGG  74
RIOK3   18  23453502    GCAAGACTTT  69

순서는 내 목적과 관련이 없습니다. 먼저 필드 5에서 정렬한 다음 필드 3에서 정렬하는 솔루션을 찾았습니다. 이것이 효과가 있다고 생각합니다.

sort -k 5,5nr input | sort -u -k 3,3n > output

이는 모든 테스트 파일에서 작동하며 어떤 경우에도 작동해야 한다고 생각합니다. 이렇게 하면 필드 3의 모든 값에 대해 정렬이 먼저 필드 5의 값이 가장 높은 행을 확인하고 유지하게 되기 때문입니다.

하지만 이 문제에 대한 좀 더 우아한(어쩌면 더 확실한) 해결책이 있어야 한다고 생각합니다. 도움을 주시면 감사하겠습니다.

답변1

출력할 데이터가 메모리에 들어갈 만큼 작은 경우

awk '
    biggest[$3] < $5 { biggest[$3]=$5 ; saved[$3]=$0 }
    END { for (i in saved) { print saved[i] }}' 

일반적으로 이 방법이 더 빠르며 저장해야 하는지 결정할 때 각 행을 한 번 살펴봐야 합니다. 메모리 요구 사항은 출력되는 데이터에 따라 다르므로 매우 반복적인 입력은 매우 클 수 있습니다.

이는 행당 여러 비교가 필요한 정렬 솔루션과 대조됩니다. 정렬 기반 솔루션은 속도가 느리지만 너무 커서 메모리에 맞지 않는 출력을 처리합니다.

답변2

두 번째 및 세 번째 필드를 기준으로 정렬하고 awk최대값을 유지하기 위해 전달합니다.

$ sort -k 3,3nr -k 5,5rn input | awk '!a[$3]++' 
SMURF1  7   99143726    GACAGATTGG  74
CSNK1D  17  82251379    AATTTAGCCA  68
UBE2Z   17  48910880    CTAAGGATCC  48
AC003665.1  17  47813266    AGCAGGCGCA  83
RIOK3   18  23453502    GCAAGACTTT  69

이는 파일이 한 번만 정렬되고 전체 파일을 메모리에 보관할 필요가 없다는 장점이 있습니다. 그러나 나는 희망한다Icarus의 awk 메소드파일을 한 번만 읽으면 되므로 더 빠릅니다.

관련 정보