将两个向量与所有向量元素的组合粘贴

我有两个向量:

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"

如何创建我需要的矢量?

50265 次浏览

You can use this, but there may be a simpler solution :

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

expand.grid gives back a data.frame which when used with apply, apply will convert it to a matrix. This is just unnecessary (and inefficient on large data). outer gives a matrix and also takes function argument. It'll be much efficient on huge data as well.

Using outer:

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

To maintain the order of the requested strings in the question, you can use these two modifications of both methods:

Change order of vectors and combine in reverse order

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"

or transpose the matrix before converting to vector:

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

Another option using sprintf in combination with expand.grid:

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

which gives:

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

Explanation:

  • With expand.grid you create all combinations of the two vectors.
  • sprintf pastes the two vectors together according to the specified format ('%s.%s'). Each %s part of the format is replaced by the elements of the vectors.

This old question already has an accepted answer. But as it's being used as dupe target, I believe it's worthwhile to add a data.table solution which uses the cross join function 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"

In case the original order is important:

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

Edit: CJ() has changed default behaviour with version 1.12.0

As announced in the release notes of version 1.12.0 (Point 3) the default option options(datatable.CJ.names=TRUE) has changed. CJ() now auto-names its inputs exactly as data.table() does.

So, the code above has to be amended for data.table version 1.12.0 and above:

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

and

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

resp.

Another option is to use the each argument of rep:

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

I find this more straightforward than the solutions based on apply or expand.grid.

Some other options with 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"

We can also use cross2

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

option with dplyr copied from this link

    fruits <- tibble(
type   = c("apple", "orange", "apple", "orange", "orange", "orange"),
year   = c(2010, 2010, 2012, 2010, 2010, 2012),
size  =  factor(
c("XS", "S",  "M", "S", "S", "M"),
levels = c("XS", "S", "M", "L")
),
weights = rnorm(6, as.numeric(size) + 2)
)

All possible combinations, i.e. all are defined, but not necessarily present in the data

fruits %>% expand(type)
#> # A tibble: 2 x 1
#>   type
#>   <chr>
#> 1 apple
#> 2 orange
fruits %>% expand(type, size)
#> # A tibble: 8 x 2
#>   type   size
#>   <chr>  <fct>
#> 1 apple  XS
#> 2 apple  S
#> 3 apple  M
#> 4 apple  L
#> 5 orange XS
#> 6 orange S
#> 7 orange M
#> 8 orange L
b<-fruits %>% expand(type, size, year)
#> # A tibble: 16 x 3
#>    type   size   year
#>    <chr>  <fct> <dbl>
#>  1 apple  XS     2010
#>  2 apple  XS     2012
#>  3 apple  S      2010
#>  4 apple  S      2012
#>  5 apple  M      2010
#>  6 apple  M      2012
#>  7 apple  L      2010
#>  8 apple  L      2012
#>  9 orange XS     2010
#> 10 orange XS     2012
#> 11 orange S      2010
#> 12 orange S      2012
#> 13 orange M      2010
#> 14 orange M      2012
#> 15 orange L      2010
#> 16 orange L      2012

Then a simple paste

b <- fruits %>% expand(type, size, year) %>%
mutate(., pasted=paste(type, size, year, sep="."))

The simplest solution will just be

paste0(vars,".", vis)
[1] "SR.1" "PL.2" "SR.3"