그룹별 uniq 명령?

그룹별 uniq 명령?

다음 형식의 파일에서 가져오는 명령을 찾고 있습니다.

hello 32
hello 67
hi    2
ho    1212
ho    1390
ho    3000

다음 형식으로("그룹"의 마지막 행을 가져와 중복 제거):

hello 67
hi    2
ho    3000

현재 저는 Python과 pandas 스니펫을 사용하고 있습니다.

    df = pd.read_csv(self.input().path, sep='\t', names=('id', 'val'))

    # how to replace this logic with shell commands?
    surface = df.drop_duplicates(cols=('id'), take_last=True)

    with self.output().open('w') as output:
        surface.to_csv(output, sep='\t', cols=('id', 'val'))

업데이트: 훌륭한 답변에 감사드립니다. 다음은 몇 가지 벤치마크입니다.

입력 파일은 246M이고 8583313줄을 포함합니다. 순서는 중요하지 않습니다. 첫 번째 열의 크기는 9자로 고정되어 있습니다.

입력 파일의 예:

000000027       20131017023259.0        00
000000027       20131017023259.0        11
000000035       20130827104320.0        01
000000035       20130827104320.0        04
000000043       20120127083412.0        01
...

                              time        space complexity

tac .. | sort -k1,1 -u        27.43682s   O(log(n))
Python/Pandas                 11.76063s   O(n)
awk '{c[$1]=$0;} END{for(...  11.72060s   O(n)

첫 번째 열의 길이는 고정되어 있으므로 다음을 uniq -w사용할 수도 있습니다.

tac {input} | uniq -w 9        3.25484s   O(1)

답변1

이상해 보이지만 더 나은 방법이 있기를 바랍니다. 하지만 다음과 같습니다.

tac foo | sort -k 1,1 -u

tac파일을 되돌리는 데 사용되므로 첫 번째 파일이 아닌 마지막 파일을 얻습니다.

-k 1,1비교를 위해 첫 번째 필드만 사용한다고 합니다.

-u독특하게 만들어줍니다.

답변2

출력 순서가 마음에 들지 않으면 awk해결 방법은 다음과 같습니다.

$ awk '
    {a[$1] = !a[$1] ? $2 : a[$1] < $2 ? $2 : a[$1]}
    END {
        for (i in a) { print i,a[i] }
    }
' file
hi 2
hello 67
ho 3000

답변3

추가 옵션:

  1. perl, 줄의 순서에 관심이 없다면.

    perl -lane '$k{$F[0]}=$F[1]; END{print "$_ $k{$_}" for keys(%k)}' file
    
  2. 더 간단한awk

    awk '{c[$1]=$0;} END{for(i in c){print c[i]}}' file
    
  3. 어리석은 껍질 하나

    while read a b; do grep -w ^"$a" file | tail -n1 ; done < file | uniq
    

답변4

글쎄, 당신은 그것을 할 수 있습니다sort

sort -u -k1,1 test

편집하다:택이 해결책이다

관련 정보