blob: 098e96e6954b5d3355ca82abb27543bb9ae6a7dd [file] [log] [blame]
# File src/library/utils/R/combn.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2013 The R Core Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/
combn <- function(x, m, FUN = NULL, simplify = TRUE, ...)
{
## DATE WRITTEN: 14 April 1994 LAST REVISED: 10 July 1995
## AUTHOR: Scott Chasalow
##
## DESCRIPTION:
## Generate all combinations of the elements of x taken m at a time.
## If x is a positive integer, returns all combinations
## of the elements of seq(x) taken m at a time.
## If argument "FUN" is not null, applies a function given
## by the argument to each point. If simplify is FALSE, returns
## a list; else returns a vector or an array. "..." are passed
## unchanged to function given by argument FUN, if any.
stopifnot(length(m) == 1L, is.numeric(m))
if(m < 0) stop("m < 0", domain = NA)
if(is.numeric(x) && length(x) == 1L && x > 0 && trunc(x) == x)
x <- seq_len(x)
n <- length(x)
if(n < m) stop("n < m", domain = NA)
x0 <- x
if(simplify) {
if(is.factor(x)) x <- as.integer(x)
}
m <- as.integer(m)
e <- 0
h <- m
a <- seq_len(m)
nofun <- is.null(FUN)
if(!nofun && !is.function(FUN))
stop("'FUN' must be a function or NULL")
# first result : what kind, what length,.. ?
len.r <- length(r <- if(nofun) x[a] else FUN(x[a], ...))
count <- as.integer(round(choose(n, m))) # >= 1
if(simplify) {
dim.use <-
if(nofun)
c(m, count) # matrix also when count = 1
else {
d <- dim(r)
if(length(d) > 1L)
c(d, count)
else if(len.r > 1L)
c(len.r, count)
else # MM: *still* a matrix - a la "drop = FALSE"
c(d, count)
} ## NULL in all 'else' cases
}
if(simplify)
out <- matrix(r, nrow = len.r, ncol = count) # matrix for now
else {
out <- vector("list", count)
out[[1L]] <- r
}
if(m > 0) {
i <- 2L
nmmp1 <- n - m + 1L # using 1L to keep integer arithmetic
while(a[1L] != nmmp1) {
if(e < n - h) {
h <- 1L
e <- a[m]
j <- 1L
}
else {
e <- a[m - h]
h <- h + 1L
j <- 1L:h
}
a[m - h + j] <- e + j
r <- if(nofun) x[a] else FUN(x[a], ...)
if(simplify) out[, i] <- r else out[[i]] <- r
i <- i + 1L
}
}
if(simplify) {
if(is.factor(x0)) {
levels(out) <- levels(x0)
class(out) <- class(x0)
}
dim(out) <- dim.use
}
out
}