Ordinare in modo ottimale un set di dati di N chiavi quando la prima chiave è già ordinata


2

Mi imbatto spesso nella situazione in cui i dati parzialmente ordinati devono essere ordinati. La prima colonna è già ordinata, quelle successive non lo sono. Come in questo esempio di due colonne:

1 5
1 3
2 10
2 -1
2 3
3 11
3 -200
3 20

L'output desiderato è quello prodotto da

sort -k 1,1g -k 2,2g

che funziona ma ha il problema che nulla uscirà dall'ordinamento fino a quando non sarà stato letto tutto l'input. Quando l'input è di diversi gigabyte di testo, ciò può richiedere del tempo, durante il quale non può essere eseguito nulla a valle dell'ordinamento in una pipeline. Inoltre, non è molto efficiente in termini di utilizzo della memoria poiché l'intero set di dati deve risiedere immediatamente lì, anche se per ottenere l'ordinamento desiderato, solo una piccola parte deve davvero essere lì.

Con una sceneggiatura non sarebbe difficile suddividerla in blocchi e quindi ordinare ogni blocco. Il comando sort ha un'opzione da qualche parte per notificarlo che i dati in quella colonna sono già ordinati? Non lo vedo in ordine 8.4, ma forse mi è mancato?

Se l'ordinamento rileva un valore fuori ordine nella colonna, gli è stato detto che è già stato ordinato, dovrebbe uscire. Ciò indica un errore nell'elaborazione a monte.


Sei sicuro di aver bisogno g? Non nsarebbe abbastanza?
Choroba,

Risposte:


1

Non posso farlo con la sogliola sort. Potrebbe non essere possibile.

Nella mia soluzione awkgestisce la prima colonna ed esegue sorttutte le volte che è necessario. Lo script prende input da stdin, stampa su stdout).

#!/usr/bin/awk -f

BEGIN { command = "sort -k 2,2g" }

{
if ( NR==1 ) {
   val=$1
   buf=$0
}
else
if ( $1 < val ) {
   print "Unsorted 1st column detected. Processing last valid chunk and aborting." > "/dev/stderr"
   exit 1
   }
else {
if ( $1 == val )
   buf=buf"\n"$0
else
   {
   print buf | command
   close(command)
   buf=$0
   val=$1
   }
   }
}

END { print buf | command }

Appunti:

  • close(command)è fondamentale. Senza di essa, tutte le pipe per commandandare a un singolo sort .
  • Secondo me gli awkoperatori di confronto gestiscono i numeri abbastanza bene. Per essere veramente sicuri che la soluzione sortfunzioni come dovrebbe funzionare, è necessario recuperare lo stato di uscita di sort -c -k 1,1gfor val"\n"$1e separatamente per $1"\n"val, quindi costruire la logica di script su quello. Ciò avrebbe eseguito due sortprocessi per riga di input, mi aspetto un enorme successo in termini di prestazioni.

0

Perl in soccorso!

Fa esattamente quello che hai chiesto, convoglia pezzi di input che iniziano con lo stesso numero per ordinare che opera solo sulla seconda colonna.

#!/usr/bin/perl
use warnings;
use strict;

my $sort;

my $first = -1;
while (<>) {
    my ($x, $y) = split;
    if ($first != $x) {
        die "Unsorted line $." if $first > $x;
        $first = $x;
        open $sort, '|-', 'sort -k2,2n' or die $!;
    }
    print {$sort} $_;
}

L'unico problema potrebbe essere il valore iniziale di $first: Se l'input inizia con un numero negativo nella prima colonna, è necessario specificare un valore inferiore.

Ho usato l' nordinamento invece di gcome sembra un po 'più veloce sulla mia macchina.


0

Kamil Cuk ha pubblicato questa risposta nell'altra discussione. Ora proverò a eliminare quel thread, dato che apparentemente avere questo in due posti è un no no, e vorrei preservare questa risposta qui.

Lo script seguente stampa le linee con la stessa prima colonna in un file temporaneo e lo ordina.

file=$1
# create temporary file
temp=$(mktemp)
trap 'rm "$temp"' EXIT
i_last=""
while read -r i j; do
    if [ "$i" != "$i_last" ]; then
        # output sorted temporary file
        sort -n $temp
        # and truncate temporary file
        > $temp
        # increment first column pointer
        i_last=$i
    fi
    # print all lines into temporary file
    echo "$i" "$j" >>$temp
done <"$file"
# dont forget leftovers
sort -n "$temp"

Certo, ma quello che stavo chiedendo non era come fare questo con uno script, ma piuttosto come farlo solo con Linux. Cioè, c'è un flag "presorted" di qualche tipo per una chiave.
matematica
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.