purrr (version 0.2.2)

cross_n: Produce all combinations of list elements

Description

cross2() returns the product set of the elements of .x and .y. cross3() takes an additional .z argument. cross_n() takes a list .l and returns the cartesian product of all its elements in a list, with one combination by element. cross_d() is like cross_n() but returns a data frame, with one combination by row.

Usage

cross_n(.l, .filter = NULL)
cross2(.x, .y, .filter = NULL)
cross3(.x, .y, .z, .filter = NULL)
cross_d(.l, .filter = NULL)

Arguments

.l
A list of lists or atomic vectors. Alternatively, a data frame. cross_d() requires all elements to be named.
.filter
A predicate function that takes the same number of arguments as the number of variables to be combined.
.x, .y, .z
Lists or atomic vectors.

Value

cross2(), cross3() and cross_n() always return a list. cross_d() always returns a data frame. cross_n() returns a list where each element is one combination so that the list can be directly mapped over. cross_d() returns a data frame where each row is one combination.

Details

cross_n(), cross2() and cross3() return the cartesian product is returned in wide format. This makes it more amenable to mapping operations. cross_d() returns the output in long format just as expand.grid() does. This is adapted to rowwise operations.

When the number of combinations is large and the individual elements are heavy memory-wise, it is often useful to filter unwanted combinations on the fly with .filter. It must be a predicate function that takes the same number of arguments as the number of crossed objects (2 for cross2(), 3 for cross3(), length(.l) for cross_n()) and returns TRUE or FALSE. The combinations where the predicate function returns TRUE will be removed from the result.

See Also

expand.grid()

Examples

Run this code
# We build all combinations of names, greetings and separators from our
# list of data and pass each one to paste()
data <- list(
  id = c("John", "Jane"),
  greeting = c("Hello.", "Bonjour."),
  sep = c("! ", "... ")
)

data %>%
  cross_n() %>%
  map(lift(paste))

# cross_n() returns the combinations in long format: many elements,
# each representing one combination. With cross_d() we'll get a
# data frame in long format: crossing three objects produces a data
# frame of three columns with each row being a particular
# combination. This is the same format that expand.grid() returns.
args <- data %>% cross_d()

# In case you need a list in long format (and not a data frame)
# just run as.list() after cross_d()
args %>% as.list()

# This format is often less pratical for functional programming
# because applying a function to the combinations requires a loop
out <- vector("list", length = nrow(args))
for (i in seq_along(out))
  out[[i]] <- map(args, i) %>% invoke(paste, .)
out

# It's easier to transpose and then use invoke_map()
args %>% transpose() %>% map_chr(~ invoke(paste, .))

# Unwanted combinations can be filtered out with a predicate function
filter <- function(x, y) x >= y
cross2(1:5, 1:5, .filter = filter) %>% str()

# To give names to the components of the combinations, we map
# setNames() on the product:
seq_len(3) %>%
  cross2(., ., .filter = `==`) %>%
  map(setNames, c("x", "y"))

# Alternatively we can encapsulate the arguments in a named list
# before crossing to get named components:
seq_len(3) %>%
  list(x = ., y = .) %>%
  cross_n(.filter = `==`)

Run the code above in your browser using DataLab