MichaelE
MichaelE

Reputation: 837

R how to get a result like expand.grid, but control the order of the expansion?

The expand.grid gives the results ordered by the last entered set, but I need it based on the first set.

Given the following code:

expand.grid(a=(1:2),b=c("a","b","c"))
  a b
1 1 a
2 2 a
3 1 b
4 2 b
5 1 c
6 2 c

Notice how column a changes most often with b less often.

The algorithm it seems is lock the 2nd or Nth variable b and then alternate the 1st or (N-1) variable until the grid gets to every combination possible in the grid.

I need to expand.grid or a similar function that first sets the 1st variable and then adjusts the 2nd variable and so on until it gets to all N.

The desired result for the example is:

  a b
1 1 a
2 1 b
3 1 c
4 2 a
5 2 b
6 2 c

One way I that works for the example is simply to order by column a, but that does not work as I would need to be able to order by N columns in order and I have not found a way to do so.

It seems so trivial, but I cannot find a way to get expand.grid to behave like I need.

Any solution must work on any arbitrary number of entries to expand.grid and of any arbitrary size. Thank you.

Upvotes: 3

Views: 1188

Answers (4)

Escalen
Escalen

Reputation: 341

Here is a base-R solution, that works with any amount of variables without knowing the content beforehand.

Gather all the variables in a list, with the desired order in which you want to expand. Apply a reverse function rev first on the list in expand.grid and a second time on the output to get the desired expanding result.

Your example:

l <- list(a=(1:2),b=c("a","b","c"))
rev(expand.grid(rev(l)))
#>   a b
#> 1 1 a
#> 2 1 b
#> 3 1 c
#> 4 2 a
#> 5 2 b
#> 6 2 c

An example with 3 variables:

var1 <- c("SR", "PL")
var2 <- c(1,2,3)
var3 <- c("A",'B')
l <- list(var1,var2,var3)
rev(expand.grid(rev(l)))
#>    Var3 Var2 Var1
#> 1    SR    1    A
#> 2    SR    1    B
#> 3    SR    2    A
#> 4    SR    2    B
#> 5    SR    3    A
#> 6    SR    3    B
#> 7    PL    1    A
#> 8    PL    1    B
#> 9    PL    2    A
#> 10   PL    2    B
#> 11   PL    3    A
#> 12   PL    3    B

Upvotes: 4

akrun
akrun

Reputation: 887951

We can use crossing from tidyr

library(tidyr)
crossing(a = 1:2, b = c('a', 'b', 'c'))
# A tibble: 6 x 2
#      a b    
#  <int> <chr>
#1     1 a    
#2     1 b    
#3     1 c    
#4     2 a    
#5     2 b    
#6     2 c    

Upvotes: 3

Yuriy Saraykin
Yuriy Saraykin

Reputation: 8880

try to do so

library(tidyverse)
df <- expand.grid(a=(1:2),b=c("a","b","c"))

df %>% 
  arrange_all()

Upvotes: 4

stefan
stefan

Reputation: 125797

Try this:

expand.grid(b=c("a","b","c"), a=(1:2))[, c("a", "b")]
#>   a b
#> 1 1 a
#> 2 1 b
#> 3 1 c
#> 4 2 a
#> 5 2 b
#> 6 2 c

Created on 2020-03-19 by the reprex package (v0.3.0)

Upvotes: 1

Related Questions