4

I want to call a function on all combinations of arguments. For that end I tried outer:

> outer(c(0,6,7),c(100,10,1,0.1,0.01),FUN=list)
Error in outer(c(0, 6, 7), c(100, 10, 1, 0.1, 0.01), FUN = list) : 
  dims [product 15] do not match the length of object [2]

I can get what I want using nested lapply:

do.call(c,lapply(c(0,6,7),function(type) 
  lapply(c(100,10,1,0.1,0.01),function(cost) 
    list(type=type,cost=cost)))

but I wonder if there is a better solution (especially if I have more than two variables, say, epsilon in addition to type and cost).

sds
  • 58,617
  • 29
  • 161
  • 278

3 Answers3

3

How about just using expand.grid to get all combinations. Generalisable to any number of vectors (arguments). You can then use apply. Feels a bit messy, but does the job...

# stick your function in the apply loop
args <- expand.grid( c(0,6,7) , c(100,10,1,0.1,0.01) )
apply( args , 1 , function(x) x[1] * x[2] )

Alternatively, the cross-join feature of data.table - the CJ function ( essentially does the same thing as expand.grid ) could come in handy, along with the fact that you can evaluate a function in the j of a data.table...

require( data.table )
dt <- CJ( cost = c(0,6,7) , type = c(100,10,1,0.1,0.01) )
dt[ , result := cost * type ]
 #   cost  type result
 #1:    0 1e-02  0e+00
 #2:    0 1e-01  0e+00
 #3:    0 1e+00  0e+00
 #4:    0 1e+01  0e+00
 #5:    0 1e+02  0e+00
 #6:    6 1e-02  6e-02
 #...snip...
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
  • 1
    I don't think they really wanted the multiplication of `outer`, they just wanted all possible combinations. I think `expand.grid` is a very good selection for this case. Perhaps you can just name those parameters: `expand.grid( type=c(0,6,7) , cost=c(100,10,1,0.1,0.01) )` – MrFlick May 27 '14 at 21:43
  • 1
    And after you have the data.frame from expand.grid, to turn it into a list of lists you can do `split(args , 1:nrow(args))` – MrFlick May 27 '14 at 21:45
0

data.table's CJ does something similar:

CJ(type = c(0, 6, 7), cost = c(100, 10, 1, 0.1, 0.01))

    type  cost
 1:    0 2e-02
 2:    0 1e-01
 3:    0 1e+00
 4:    0 1e+01
 5:    0 1e+02
 6:    6 2e-02
 7:    6 1e-01
 8:    6 1e+00
 9:    6 1e+01
10:    6 1e+02
11:    7 2e-02
12:    7 1e-01
13:    7 1e+00
14:    7 1e+01
15:    7 1e+02

You can convert each row to a list if that's what you want with apply(dt, 1, as.list)

Señor O
  • 17,049
  • 2
  • 45
  • 47
0

You could use expand.grid and mapply:

tmp = expand.grid(c(0,6,7),c(100,10,1,0.1,0.01))
do.call(".mapply",   ##".mapply" seems handier for this since you don't have to specify each `...` argument
        c(function(x, y) list(type = x, cost = y), 
          list(unname(tmp)), 
          list(NULL)))
alexis_laz
  • 12,884
  • 4
  • 27
  • 37