Wie ordne ich Zahlen in Arrays nach Unix?

7

Ich denke, ob es einen Namen für eine so einfache Funktion gibt, die die Reihenfolge der Zahlen in einem Array zurückgibt. Ich würde dieses Ranking wirklich gerne auf minimalistische Weise und mit grundlegenden Unix-Befehlen durchführen, aber ich kann mir nichts anderes vorstellen als einfaches Find-and-Loop, das nicht so elegant ist. Angenommen, Sie haben eine Reihe von Zahlen

17 
94 
3 
52 
4 
4 
9

Erwartete Ausgabe, bei der Duplikate nur dieselbe ID erhalten; Der Umgang mit Duplikaten ist nicht kritisch. Nehmen Sie also Verknüpfungen:

4 
6 
1 
5 
2 
2 
3        

Motivation: Ich habe heute viele Benutzer gesehen, die viele verschiedene Methoden zur Lösung dieses Problems verwendet und viele manuelle Schritte mit Spreadsheet ausgeführt haben. Also fing ich an, über den minimalistischen Weg nachzudenken.

Vergleich des Ranking-Algorithmus mit dem durchschnittlichen Ranking von Google

Wenn Sie dies in Google Spreadsheet tun, erhalten =arrayformula(rank.AVG(A:A,A:A,true))Sie als Benchmark eine aufsteigende Reihenfolge wie die erste erwartete Ausgabe

17  5
94  7
3   1
52  6
4   2.5
4   2.5
9   4

wo Sie sehen, dass mein anfänglicher Ranking-Algorithmus voreingenommen ist. Ich denke, dass es hier hilfreich wäre, den Speicherort des Datensatzes festlegen zu können.

Léo Léopold Hertz 준영
quelle
1
Abgesehen von der umgekehrten Reihenfolge besteht der geringfügige "voreingenommene" Unterschied darin, dass doppelte Elemente als zwei statt als eine Stelle gezählt werden.
JJoao

Antworten:

11

Wenn diese Liste in einer Liste filepro Zeile enthalten wäre, würde ich Folgendes tun:

sort -nu file |
  awk 'NR == FNR {rank[$0] = NR; next}
      {print rank[$0]}' - file

Wenn es in einem zsh $array:

sorted=(${(nou)array})
for i ($array) echo $sorted[(i)$i]

Dies ist das gleiche Prinzip wie bei der awkobigen Version. Der Rang ist der Index NR/ (i)in der numerisch ( -n/ (n)) geordneten ( sort/ (o)), eindeutigen ( -u/ (u)) Liste der Elemente.

Für Ihren durchschnittlichen Rang:

sort -n file |
  awk 'NR == FNR {rank[$0] += NR; n[$0]++; next}
  {print rank[$0] / n[$0]}' - file

Welches gibt:

5
7
1
6
2.5
2.5
4

(Verwenden Sie sort -rndiese Option, um die Reihenfolge wie in Ihrer Google Spreadsheet- Version umzukehren .)

Stéphane Chazelas
quelle
Bitte beachten Sie den Benchmark des durchschnittlichen Rankings von Google im Body. Vielleicht kann es Ihren Vorschlag vereinfachen. Es wäre großartig, den Speicherort des Datensatzes so einstellen zu können, dass er voreingenommen und / oder unvoreingenommen ist.
Léo Léopold Hertz 준영
2
@Masi, siehe Bearbeiten für durchschnittliche Rangfolge. Ich folge Ihrem Satz über voreingenommene / unvoreingenommene und Datensatzspeicherorte nicht . Möglicherweise benötigt Ihre Frage mehr Kontext.
Stéphane Chazelas
8
nl x | sort  -k 2n | nl | sort -k 2n | cut -f1

... es hat ein etwas anderes Verhalten bei Duplikaten:

 nl x | sort  -k 2n | nl | sort -k 2n | cut -f1,3
 5  17 
 7  94 
 1  3 
 6  52 
 2  4 
 3  4 
 4  9
JJoao
quelle
Bitte beachten Sie den Benchmark des durchschnittlichen Rankings von Google im Body. Vielleicht kann es Ihren Vorschlag vereinfachen. Es wäre großartig, den Speicherort des Datensatzes so einstellen zu können, dass er voreingenommen und / oder unvoreingenommen ist.
Léo Léopold Hertz 준영
1
@masi, Appart Duplikate, Sie erhalten das Google-Ranking, wenn Sie nur in umgekehrter Reihenfolge sortieren:nl x | sort -k 2rn | nl | sort -k 2n | cut -f1,3
JJoao
6

Mit nur GNU awk:

awk '
    FNR == NR {numbers[$1]=1; next} 
    FNR == 1 {
        n = asorti(numbers, sorted, "@ind_num_asc")
        for (i=1; i<=n; i++) rank[sorted[i]] = i
    }
    {print rank[$1]}
' file file
Glenn Jackman
quelle
2
Beachten Sie, dass numbers[$1]=1dies vereinfacht werden kann, numbers[$1]da Sie sich nicht um die Werte dieses Hashs kümmern.
Stéphane Chazelas
3
Ich finde das für meinen Geschmack zu dunkel und bevorzuge eine Aufgabe, um das Array-Element zu erstellen.
Glenn Jackman
1
@masi, wie wird das "Google Average Ranking" implantiert? Ich vermute sehr, dass es meinen Code überhaupt nicht vereinfachen wird
Glenn Jackman
Andererseits habe ich mich gefragt, welche Bedeutung es hat, dem Array den Wert 1 zuzuweisen. Für mich h[key]ist es idiomatisch, den Schlüssel eines Hash zuzuweisen, während a[key]=1es idiomatisch wäre , dem Hash-Element von durch diesen Schlüssel einen wahren Wert zu geben .
Stéphane Chazelas