blob: 9c125024c042c3f10ccf7a8b2f184a1d45a5940e [file] [log] [blame]
# File src/library/base/R/tapply.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2017 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/
tapply <- function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
{
FUN <- if (!is.null(FUN)) match.fun(FUN)
if (!is.list(INDEX)) INDEX <- list(INDEX)
INDEX <- lapply(INDEX, as.factor)
nI <- length(INDEX) # now, 'INDEX' is not classed
if (!nI) stop("'INDEX' is of length zero")
if (!all(lengths(INDEX) == length(X)))
stop("arguments must have same length")
namelist <- lapply(INDEX, levels)#- all of them, yes !
extent <- lengths(namelist, use.names = FALSE)
cumextent <- cumprod(extent)
if (cumextent[nI] > .Machine$integer.max)
stop("total number of levels >= 2^31")
storage.mode(cumextent) <- "integer"
ngroup <- cumextent[nI]
group <- as.integer(INDEX[[1L]]) #- to contain the splitting vector
if (nI > 1L)
for (i in 2L:nI)
group <- group + cumextent[i - 1L] * (as.integer(INDEX[[i]]) - 1L)
if (is.null(FUN)) return(group)
levels(group) <- as.character(seq_len(ngroup))
class(group) <- "factor"
ans <- split(X, group) # use generic, e.g. for 'Date'
names(ans) <- NULL
index <- as.logical(lengths(ans)) # equivalently, lengths(ans) > 0L
ans <- lapply(X = ans[index], FUN = FUN, ...)
ansmat <- array(
if (simplify && all(lengths(ans) == 1L)) {
ans <- unlist(ans, recursive = FALSE, use.names = FALSE)
if(!is.null(ans) && is.na(default) && is.atomic(ans))
vector(typeof(ans))
else default
} else vector("list", prod(extent)),
dim = extent, dimnames = namelist)
if(length(ans)) {
ansmat[index] <- ans
}
ansmat
}