Как отсортировать один вектор на основе значений другого

112

У меня есть вектор x, который я хотел бы отсортировать по порядку значений в векторе y. Два вектора не одинаковой длины.

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

Ожидаемый результат:

[1] 4 4 4 2 2 1 3 3 3
Ученик
источник

Ответы:

70

Вот один лайнер ...

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

[править:] Это разбивается следующим образом:

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
Это очень лаконично, но мне трудно понять, что там происходит. Не могли бы вы немного уточнить?
Мэтт Паркер,
3
Это красиво и показывает хорошее понимание встроенных функций R. +1
Годеке
6
В общем, можно захотеть сделать это, даже если y не является перестановкой 1: length (y). В этом случае это решение не работает, но решение gd047 ниже, x [order (match (x, y))], работает.
Рахул Савани
5
Я действительно сбит с толку, почему у него 40 голосов. Так много простых вариаций на xи y. x <- c(1,4,2); y <- c(1,2,4)например.
thelatemail
1
@thelatemail Согласен. Остановите безумие и проголосуйте против этого ответа!
Ian Fellows
185

что насчет этого

x[order(match(x,y))]
Джордж Донтас
источник
29
Это очень хорошо, лучше, чем принятый ответ, ИМХО, поскольку он более общий.
fmark
2
Я бы сказал, что это должно быть в базе GNU-R.
катастрофическая неисправность
Этот ответ хорошо сработал для меня при использовании векторов символов как для x, так и для y. Было бы неплохо добавить декомпозицию / небольшую проработку, как в принятом ответе
mavericks
4

Вы можете преобразовать xв упорядоченный коэффициент:

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

Очевидно, что преобразование ваших чисел в факторы может радикально изменить то, как реагирует нижестоящий код x. Но поскольку вы не дали нам никакого контекста о том, что будет дальше, я подумал, что предлагаю это как вариант.

Мэтт Паркер
источник
1
это должен быть лучший ответ, поскольку он будет работать для нецелочисленных случаев; или также работать, когда значения xне в векторе сортировки yс небольшим изменением: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

Как насчет?:

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

(Иэн, наверное, еще лучше)

Бен Болкер
источник
2

Если вам нужно навести порядок по «y», независимо от того, цифры это или символы:

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

По шагам:

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: Ясно, что у Йена правильный подход, но я оставлю это для потомков.]

Вы можете сделать это без циклов, индексируя свой вектор y. Добавьте увеличивающееся числовое значение к y и объедините их:

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

Результат в z: 4 4 4 2 2 1 3 3 3

Важные шаги:

  1. for (i in y) - перебирает интересующие элементы.

  2. z <- c (z, ...) - объединяет каждое подвыражение по очереди

  3. rep (i, sum (x == i)) - повторяет i (текущий интересующий элемент) sum (x == i) раз (сколько раз мы нашли i в x).

Годеке
источник
0

Также вы можете использовать sqldfи делать это с помощью следующей joinфункции sql:

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]]
О, мой бог
источник