Wie sortiere ich einen Vektor anhand der Werte eines anderen

112

Ich habe einen Vektor x, den ich basierend auf der Reihenfolge der Werte in Vektor y sortieren möchte. Die beiden Vektoren sind nicht gleich lang.

x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3)
y <- c(4, 2, 1, 3)

Das erwartete Ergebnis wäre:

[1] 4 4 4 2 2 1 3 3 3
learnr
quelle

Antworten:

70

Hier ist ein Einzeiler ...

y[sort(order(y)[x])]

[edit:] Dies gliedert sich wie folgt:

order(y)             #We want to sort by y, so order() gives us the sorting order
order(y)[x]          #looks up the sorting order for each x
sort(order(y)[x])    #sorts by that order
y[sort(order(y)[x])] #converts orders back to numbers from orders
Ian Fellows
quelle
1
Das ist sehr prägnant, aber es fällt mir schwer herauszufinden, was dort vor sich geht. Könnten Sie etwas näher darauf eingehen?
Matt Parker
3
Dies ist hübsch und zeigt ein gutes Verständnis der integrierten Funktionen von R. +1
Godeke
6
Im Allgemeinen kann man dies auch dann tun, wenn y keine Permutation von 1: Länge (y) ist. In diesem Fall funktioniert diese Lösung nicht, aber die unten stehende Lösung von gd047, x [order (match (x, y))], funktioniert.
Rahul Savani
5
Ich bin wirklich verblüfft, warum dies 40 positive Stimmen hat. Es schlägt bei so vielen einfachen Variationen von xund fehl y. x <- c(1,4,2); y <- c(1,2,4)zum Beispiel.
E-Mail
1
@thelatemail Ich stimme zu. Stoppen Sie den Wahnsinn und stimmen Sie diese Antwort ab!
Ian Fellows
184

was ist mit diesem

x[order(match(x,y))]
George Dontas
quelle
29
Dies ist sehr schön, besser als die akzeptierte Antwort IMHO, da es allgemeiner ist.
Mark
2
Ich würde sogar sagen, dass dies in der Basis GNU-R sein sollte.
katastrophaler Ausfall
Diese Antwort hat bei der Verwendung von Zeichenvektoren sowohl für x als auch für y gut funktioniert. Eine Zerlegung / leichte Ausarbeitung wie in der akzeptierten Antwort hinzuzufügen wäre schön
Außenseiter
4

Sie könnten xin einen geordneten Faktor umrechnen :

x.factor <- factor(x, levels = y, ordered=TRUE)
sort(x)
sort(x.factor)

Offensichtlich kann die Änderung Ihrer Zahlen in Faktoren die Art und Weise, wie Code nachgeschaltet reagiert, radikal verändern x. Aber da Sie uns keinen Kontext darüber gegeben haben, was als nächstes passiert, dachte ich, ich würde dies als Option vorschlagen.

Matt Parker
quelle
1
Dies sollte die beste Antwort sein, da dies für nicht ganzzahlige Fälle funktionieren würde. oder auch arbeiten, wenn es Werte in xnicht im Sortiervektor ymit geringfügiger Änderung gibt:x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3, 6); y <- c(4, 2, 1, 3); as.numeric(as.character(sort(factor(x, unique(c(y, x))))))
rawr
2

Wie wäre es mit?:

rep(y,table(x)[as.character(y)])

(Ians ist wahrscheinlich noch besser)

Ben Bolker
quelle
2

Falls Sie eine Bestellung für "y" benötigen, egal ob es sich um Zahlen oder Zeichen handelt:

x[order(ordered(x, levels = y))]
4 4 4 2 2 1 3 3 3

Schritt für Schritt:

a <- ordered(x, levels = y) # Create ordered factor from "x" upon order in "y".
[1] 2 2 3 4 1 4 4 3 3
Levels: 4 < 2 < 1 < 3

b <- order(a) # Define "x" order that match to order in "y".
[1] 4 6 7 1 2 5 3 8 9

x[b] # Reorder "x" according to order in "y".
[1] 4 4 4 2 2 1 3 3 3
Georgie Shimanovsky
quelle
1

[ Bearbeiten: Natürlich hat Ian den richtigen Ansatz, aber ich werde dies der Nachwelt überlassen.]

Sie können dies ohne Schleifen tun, indem Sie Ihren y-Vektor indizieren. Fügen Sie y einen inkrementellen numerischen Wert hinzu und führen Sie sie zusammen:

y <- data.frame(index=1:length(y), x=y)
x <- data.frame(x=x)
x <- merge(x,y)
x <- x[order(x$index),"x"]
x
[1] 4 4 4 2 2 1 3 3 3
Shane
quelle
0
x <- c(2, 2, 3, 4, 1, 4, 4, 3, 3)
y <- c(4, 2, 1, 3)
for(i in y) { z <- c(z, rep(i, sum(x==i))) }

Das Ergebnis in z: 4 4 4 2 2 1 3 3 3

Die wichtigen Schritte:

  1. for (i in y) - Schleifen über die interessierenden Elemente.

  2. z <- c (z, ...) - Verkettet nacheinander jeden Unterausdruck

  3. rep (i, sum (x == i)) - Wiederholt i (das aktuelle interessierende Element) sum (x == i) mal (die Häufigkeit, mit der wir i in x gefunden haben).

Godeke
quelle
0

Sie können sqldfes auch mit einer joinFunktion sqlwie folgt verwenden und ausführen:

library(sqldf)
x <- data.frame(x = c(2, 2, 3, 4, 1, 4, 4, 3, 3))
y <- data.frame(y = c(4, 2, 1, 3))

result <- sqldf("SELECT x.x FROM y JOIN x on y.y = x.x")
ordered_x <- result[[1]]
Oh mein Gott
quelle