Learn R Programming

purrr (version 0.1.0)

cross2: Produce all combinations of list elements

Description

cross2() returns the product set of the elements of .x and .y. It is similar to expand.grid() but it returns a list. By default, the cartesian product is returned in wide format. This makes it more amenable to mapping operations. Switching .wide to FALSE turns the output to the long format, the equivalent to expand.grid()'s outputs.

Usage

cross2(.x, .y, .filter = NULL)

cross3(.x, .y, .z, .filter = NULL)

cross_n(.l, .filter = NULL)

cross_d(.l, .filter = NULL)

Arguments

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

Value

  • cross2(), cross3() and cross_n() always return a list. cross_d() always returns a data frame if .l is 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

cross3() takes three three arguments instead of two and returns the cartesian product of the elements of the three objects. 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 similar but returns a data frame, with one combination by row.

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. .filter 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_dl(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. If we cross three objects, we'll get 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 a list (as opposed to a data frame) in long format is
# needed, 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) %>% map_call("paste")
out

# In this case, the combinations could be manipulated using dplyr
args %>% dplyr::do(
  map_call(., "paste") %>% dplyr::data_frame()
)

# 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 = function(x, y) x == y) %>%
  map(setNames, c("x", "y"))

# We can also encapsulate the arguments in a named list before
# crossing:
seq_len(3) %>%
  list(x = ., y = .) %>%
  cross_n(.filter = ~ .x == .y)

Run the code above in your browser using DataLab