Pasting two vectors with combinations of all vectors' elements

RR Faq

R Problem Overview


I have two vectors:

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

Based on these vectors I would like to create the following vector:

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

With paste I have the following result:

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

How can I create the vector I need?

R Solutions


Solution 1 - R

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"

Solution 2 - R

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.

Solution 3 - R

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.

Solution 4 - R

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][1] (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. [1]: https://github.com/Rdatatable/data.table/blob/master/NEWS.md#notes

Solution 5 - R

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"

Solution 6 - R

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"

Solution 7 - R

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="."))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDSSSView Question on Stackoverflow
Solution 1 - RjubaView Answer on Stackoverflow
Solution 2 - RewancarrView Answer on Stackoverflow
Solution 3 - RJaapView Answer on Stackoverflow
Solution 4 - RUweView Answer on Stackoverflow
Solution 5 - RCCIDView Answer on Stackoverflow
Solution 6 - RRonak ShahView Answer on Stackoverflow
Solution 7 - RandemexoaxView Answer on Stackoverflow