GNU sort stabilne sortowanie, gdy sort nie zna kolejności sortowania

18

Mam plik dwukolumnowy; plik jest już posortowany tak, jak chcę, w kolumnie 1. Chciałbym posortować według kolumny 2, w ramach każdej kategorii kolumny 1. Nie sortrozumie jednak kolejności sortowania w kolumnie 1.

Normalny sposób (z podobnych pytań tutaj na stosie) byłby następujący:

sort --stable -k1,1 -k2,2n

Ale nie mogę określić sortowania na k1, ponieważ jest to arbitralne.

Przykładowe dane wejściowe:

C 2
C 1
A 2
A 1
B 2 
B 1

i wyjście:

C 1
C 2
A 1
A 2
B 1 
B 2
Evan Benn
źródło

Odpowiedzi:

20

Możesz użyć awk, aby rozpocząć nowe sortowanie dla każdego bloku:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} - gdy zapisana wartość jest inna, mamy nowy blok, więc zamykamy wszystkie rozpoczęte wcześniej sort
  • {print | "sort -k2,2"}'przesyła dane wyjściowe do sort, uruchamiając je, jeśli jeszcze nie jest uruchomione (awk może śledzić polecenia, które uruchamia)
muru
źródło
2
awk jest naprawdę niesamowity. Lubię to bardziej niż się spodziewałem, co było niesamowitym dekorowaniem, sortowaniem i dekorowaniem!
Evan Benn
Próbowałem porównać tę odpowiedź z drugą odpowiedzią, nie jestem pewien, dlaczego ta zużywa więcej zasobów ... Jakieś pomysły? gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn
Ile przejechałeś średnio?
muru
Nie uśredniłem, ale powtarzam i badam spójne środowiska wykonawcze.
Evan Benn
Oto podobny plik do tego, którego używam, jeśli chcesz zbadać:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn
12

Możesz użyć transformacji Schwartziana (jest to w zasadzie podejście do dekorowania, sortowania i dekorowania, o którym wspomniałeś w komentarzu, ale prawdopodobnie bardziej wydajne niż dokładna odpowiedź Muru ze względu na użycie pojedynczego wywołania zamiast wielu) - używając kolumny z prefiksem, która przyrosty ze zmianą wartości w pierwszej kolumnie, posortuj według kolumny prefiksu, a następnie kolumny „drugiej” (której pozycja porządkowa została tymczasowo przesunięta z powodu obecności kolumny prefiksu), i na koniec pozbądź się kolumny prefiksusortawk3

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-
iruvar
źródło
Jestem zaskoczony, ale masz rację, to było szybsze niż druga odpowiedź! 3 minuty w porównaniu do 2 minut na moim 100 milionowym pliku liniowym (~ 30 pierwszych kolumn uniq).
Evan Benn
1
Nie trzeba przechowywać tablicy unikalnego klucza z pierwszej kolumny. Myślę, że powinno wystarczyć porównanie pierwszej kolumny bieżącego wiersza z poprzednim.
Kusalananda
Coś jak awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(niesprawdzone).
Kusalananda