Comment trier un vecteur en fonction des valeurs d'un autre


112

J'ai un vecteur x, que je voudrais trier en fonction de l'ordre des valeurs dans le vecteur y. Les deux vecteurs ne sont pas de la même longueur.

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

Le résultat attendu serait:

[1] 4 4 4 2 2 1 3 3 3

Réponses:


70

Voici un one-liner ...

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

[modifier:] Cela se décompose comme suit:

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

1
C'est très succinct, mais j'ai du mal à comprendre ce qui se passe là-bas. Pourriez-vous élaborer un peu?
Matt Parker

3
C'est joli et montre une bonne compréhension des fonctions intégrées de R. +1
Godeke

6
En général, on peut vouloir faire cela même si y n'est pas une permutation de 1: length (y). Dans ce cas, cette solution ne fonctionne pas, mais la solution de gd047 ci-dessous, x [order (match (x, y))], le fait.
Rahul Savani

5
Je suis en fait perplexe quant à la raison pour laquelle cela a 40 votes positifs. Il échoue pour tant de variations simples sur xet y. x <- c(1,4,2); y <- c(1,2,4)par exemple.
thelatemail

1
@thelatemail Je suis d'accord. Arrêtez la folie et votez contre cette réponse!
Ian Fellows

184

et celui-là

x[order(match(x,y))]

29
C'est très gentil, mieux que la réponse acceptée à mon humble avis car elle est plus générale.
fmark

2
J'irais jusqu'à dire que cela devrait être dans la base GNU-R.
panne catastrophique

Cette réponse a bien fonctionné pour moi lors de l'utilisation de vecteurs de caractères pour x et y. Ajouter une décomposition / légère élaboration comme dans la réponse acceptée serait bien
conformistes

4

Vous pouvez convertir xen un facteur ordonné:

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

Évidemment, changer vos nombres en facteurs peut changer radicalement la façon dont le code en aval réagit x. Mais puisque vous ne nous avez pas donné de contexte sur ce qui se passe ensuite, j'ai pensé que je suggérerais cela comme une option.


1
cela devrait être la meilleure réponse car cela fonctionnerait pour les cas non entiers; ou fonctionne aussi quand il y a des valeurs xpas dans le vecteur de tri yavec un léger changement: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

Que diriez-vous?:

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

(Ian est probablement encore meilleur)


2

Au cas où vous auriez besoin de commander sur "y", qu'il s'agisse de chiffres ou de caractères:

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

Par étapes:

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

1

[ Edit: Clairement Ian a la bonne approche, mais je laisserai cela pour la postérité.]

Vous pouvez le faire sans boucles en indexant sur votre vecteur y. Ajoutez une valeur numérique incrémentielle à y et fusionnez-les:

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

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))) }

Le résultat en z: 4 4 4 2 2 1 3 3 3

Les étapes importantes:

  1. for (i in y) - Boucle sur les éléments d'intérêt.

  2. z <- c (z, ...) - Concatène chaque sous-expression tour à tour

  3. rep (i, sum (x == i)) - Répète i (l'élément actuel d'intérêt) sum (x == i) fois (le nombre de fois où nous avons trouvé i dans x).


0

Vous pouvez également l'utiliser sqldfet le faire par une joinfonction sqlcomme suit:

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]]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.