Bagaimana cara mengurutkan satu vektor berdasarkan nilai-nilai lainnya

112

Saya memiliki vektor x, yang ingin saya sortir berdasarkan urutan nilai dalam vektor y. Kedua vektor tidak memiliki panjang yang sama.

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

Hasil yang diharapkan adalah:

[1] 4 4 4 2 2 1 3 3 3
learnr
sumber

Jawaban:

70

Ini satu kapal ...

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

[edit:] Ini memecah sebagai berikut:

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
sumber
1
Itu sangat ringkas, tapi saya kesulitan mencari tahu apa yang terjadi di sana. Bisakah Anda menjelaskan sedikit?
Matt Parker
3
Ini cantik dan menunjukkan pemahaman yang baik tentang built-in R. +1
Godeke
6
Secara umum orang mungkin ingin melakukan ini meskipun y bukan permutasi dari 1: panjang (y). Dalam kasus ini, solusi ini tidak berfungsi, tetapi solusi gd047 di bawah, x [order (match (x, y))], berfungsi.
Rahul Savani
5
Saya sebenarnya bingung mengapa ini memiliki 40 suara positif. Gagal untuk begitu banyak variasi sederhana pada xdan y. x <- c(1,4,2); y <- c(1,2,4)misalnya.
thelatemail
1
@thelatemail Saya setuju. Hentikan kegilaan dan kurangi jawaban ini!
Ian Fellows
184

bagaimana dengan yang satu ini

x[order(match(x,y))]
George Dontas
sumber
29
Ini sangat bagus, lebih baik daripada jawaban yang diterima IMHO karena lebih umum.
fmark
2
Saya akan mengatakan lebih jauh bahwa ini harus dalam basis GNU-R.
bencana-kegagalan
Jawaban ini bekerja dengan baik untuk saya saat menggunakan vektor karakter untuk x dan y. Menambahkan dekomposisi / sedikit elaborasi seperti pada jawaban yang diterima akan menyenangkan
mavericks
4

Anda dapat mengubahnya xmenjadi faktor yang dipesan:

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

Jelas, mengubah angka Anda menjadi faktor dapat secara radikal mengubah cara kode downstream bereaksi x. Tetapi karena Anda tidak memberi kami konteks apa pun tentang apa yang terjadi selanjutnya, saya pikir saya akan menyarankan ini sebagai opsi.

Matt Parker
sumber
1
ini harus menjadi jawaban terbaik karena akan bekerja untuk kasus non integer; atau juga bekerja ketika ada nilai di xtidak dalam vektor pengurutan ydengan sedikit perubahan: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

Bagaimana tentang?:

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

(Ian mungkin masih lebih baik)

Ben Bolker
sumber
2

Jika Anda perlu mendapatkan urutan pada "y" tidak peduli apakah itu angka atau karakter:

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

Dengan langkah-langkah:

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
sumber
1

[ Sunting: Jelas Ian memiliki pendekatan yang benar, tapi saya akan membiarkan ini untuk anak cucu.]

Anda dapat melakukan ini tanpa loop dengan mengindeks vektor y Anda. Tambahkan nilai numerik yang bertambah ke y dan gabungkan:

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

Hasil di z: 4 4 4 2 2 1 3 3 3

Langkah-langkah penting:

  1. for (i in y) - Loop di atas elemen yang diminati.

  2. z <- c (z, ...) - Menggabungkan setiap subekspresi secara bergantian

  3. rep (i, sum (x == i)) - Mengulangi i (elemen minat saat ini) jumlah (x == i) kali (berapa kali kami menemukan i dalam x).

Godeke
sumber
0

Anda juga dapat menggunakan sqldfdan melakukannya dengan joinfungsi sqlseperti berikut:

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 Tuhan
sumber