Вставка двух векторов комбинациями элементов всех векторов

У меня два вектора:

vars <- c("SR", "PL")
vis <- c(1,2,3)

На основе этих векторов я хотел бы создать следующий вектор:

"SR.1"  "SR.2"  "SR.3"  "PL.1"  "PL.2"  "PL.3"

С paste я получаю следующий результат:

paste(vars, vis, sep=".")
 [1] "SR.1" "PL.2" "SR.3"

Как создать нужный мне вектор?


person DSSS    schedule 22.04.2013    source источник


Ответы (6)


Вы можете использовать это, но может быть более простое решение:

R> apply(expand.grid(vars, vis), 1, paste, collapse=".")
[1] "SR.1" "PL.1" "SR.2" "PL.2" "SR.3" "PL.3"

expand.grid возвращает data.frame, который при использовании с apply, apply преобразует его в matrix. Это просто ненужно (и неэффективно для больших данных). outer дает matrix и также принимает аргумент функции. Это также будет очень эффективно для больших объемов данных.

Использование outer:

as.vector(outer(vars, vis, paste, sep="."))
# [1] "SR.1" "PL.1" "SR.2" "PL.2" "SR.3" "PL.3"
person juba    schedule 22.04.2013
comment
expand.grid возвращает таблицу, которую можно отсортировать, если вы хотите, чтобы порядок был SR,SR,PL,PL..., а не SR,PL,SR,PL. - person rmf; 15.03.2019

Другой вариант - использовать аргумент each для rep:

paste(rep(vars, each = length(vis)), vis, sep = ".")

Я считаю это более простым, чем решения, основанные на apply или expand.grid.

person ewancarr    schedule 18.05.2018

Другой вариант использования sprintf в сочетании с expand.grid:

eg <- expand.grid(vis, vars)
sprintf('%s.%s', eg[,2], eg[,1])

который дает:

[1] "SR.1" "SR.2" "SR.3" "PL.1" "PL.2" "PL.3"

Объяснение:

  • С expand.grid вы создаете все комбинации двух векторов.
  • sprintf вставляет два вектора вместе в соответствии с указанным форматом ('%s.%s'). Каждая %s часть формата заменяется элементами векторов.
person Jaap    schedule 16.12.2016
comment
Думаю, это наиболее элегантное решение из всех предложенных! - person JelenaČuklina; 08.08.2017

Чтобы сохранить порядок запрашиваемых строк в вопросе, вы можете использовать эти две модификации обоих методов:

Измените порядок векторов и объедините в обратном порядке

apply(expand.grid(vis, vars), 1, function(x) paste(x[2], x[1], sep=".")) 
[1] "SR.1" "SR.2" "SR.3" "PL.1" "PL.2" "PL.3"

или транспонируйте матрицу перед преобразованием в вектор:

as.vector(t(outer(vars, vis, paste, sep="."))) 
[1] "SR.1" "SR.2" "SR.3" "PL.1" "PL.2" "PL.3"
person CCID    schedule 08.05.2014

На этот старый вопрос уже есть принятый ответ. Но поскольку он используется как цель для дублирования, я считаю целесообразным добавить решение data.table, которое использует функцию cross join CJ():

library(data.table) 
options(datatable.CJ.names=FALSE) # required with version version 1.12.0+
CJ(vars, vis)[, paste(V1, V2, sep =".")]
#[1] "PL.1" "PL.2" "PL.3" "SR.1" "SR.2" "SR.3"

Если первоначальный заказ важен:

CJ(vars, vis, sorted = FALSE)[, paste(V1, V2, sep =".")]
#[1] "SR.1" "SR.2" "SR.3" "PL.1" "PL.2" "PL.3"

Изменить: CJ() изменил поведение по умолчанию с версией 1.12.0

Как объявлено в примечаниях к выпуску версии 1.12.0 (Пункт 3) параметр по умолчанию options(datatable.CJ.names=TRUE) был изменен. CJ() теперь автоматически присваивает имена своим входам, в точности как as data.table().

Итак, приведенный выше код необходимо изменить для data.table версии 1.12.0 и выше:

library(data.table)   ### version 1.12.0+
CJ(vars, vis)[, paste(vars, vis, sep =".")]

а также

CJ(vars, vis, sorted = FALSE)[, paste(vars, vis, sep =".")]

соотв.

person Uwe    schedule 04.06.2017

Некоторые другие варианты с purrr:

library(purrr)
cross(list(vars, vis)) %>% map_chr(paste, sep = ".", collapse = ".")
#[1] "SR.1" "PL.1" "SR.2" "PL.2" "SR.3" "PL.3"

Мы также можем использовать cross2

cross2(vars, vis) %>%  map_chr(paste, sep = ".", collapse = ".")
#[1] "SR.1" "PL.1" "SR.2" "PL.2" "SR.3" "PL.3"
person Ronak Shah    schedule 13.01.2020