Nothing
# check.index.R
# Check that an index vector specified by the user is ok to index an object.
# We want to preclude confusing R messages or behaviour later.
# An example is when max(index) > length(object) which quietly
# returns NA and can cause confusing downstream behaviour.
# This returns a vector suitable for indexing into object (will
# be identical to index unless index is a character vector).
#
# If index is a character vector, then matching (regex if is.col.index != 2)
# is used against the names in the object, and an integer vector is returned.
check.index <- function(index, index.name, object,
colnames = NULL,
is.col.index = 0, # 0=row index, 1=col index, 2=exact non-regex col name if char
allow.empty = FALSE, # if index is char will warn if necessary regardless of allow.empty
allow.zeros = FALSE,
allow.negatives = TRUE,
allow.dups = FALSE,
treat.NA.as.one = FALSE,
is.degree.spec = FALSE) # special handling for degree1 and degree2 specs
{
index.name <- quotify.short(index.name, "index", quote="'")
# check that the given index and object can be evaluated
try <- try(eval(index))
if(is.try.err(try))
stop0("illegal ", index.name)
try <- try(eval(object))
if(is.try.err(try))
stop0("illegal ", quotify.short(object, quote="'"))
is.col.index <- check.integer.scalar(is.col.index, min=0, max=2)
allow.empty <- check.boolean(allow.empty)
allow.zeros <- check.boolean(allow.zeros)
allow.negatives <- check.boolean(allow.negatives)
allow.dups <- check.boolean(allow.dups)
treat.NA.as.one <- check.boolean(treat.NA.as.one)
if(is.null(index)) {
if(!allow.empty)
stop0(index.name, " is NULL and cannot be used as an index")
return(NULL)
}
if(treat.NA.as.one && (length(index) == 1 && is.na(index)[1]))
index <- 1
if(anyNA(index))
stop0("NA in ", index.name)
if(NROW(index) != 1 && NCOL(index) != 1)
stop0(index.name, " must be a vector not a matrix (",
index.name, " has dimensions ",
NROW(index), " x ", NCOL(index), ")")
len <- get.len(object, is.col.index)
if(is.character(index)) # currently only works for column names of object
check.character.index(index, index.name, object, colnames, len,
is.fixed=(is.col.index==2), allow.empty, is.degree.spec)
else if(is.logical(index))
check.logical.index(index, index.name, len, allow.empty)
else if(is.numeric(index))
check.numeric.index(index, index.name, len, allow.empty,
allow.negatives, allow.dups, allow.zeros, treat.NA.as.one)
else
stop0(index.name, " must be an index vector (numeric, logical, or character)")
}
get.len <- function(object, is.col.index)
{
if(is.col.index)
len <- NCOL(object) # index is for columns of object
else if(is.null(dim(object)))
len <- length(object)
else
len <- NROW(object) # index is for rows of object
# NROW also works for lists
stopifnot(length(len) == 1)
stopifnot(len > 0)
len
}
matchmult <- function(x, tab) # like match but return multiple matches if present
{
matches <- integer(0)
for(i in seq_along(x)) {
xi <- x[i]
for(itab in 1:length(tab))
if(xi == tab[itab])
matches <- c(matches, itab)
}
matches
}
# This does regex matching of index and returns an integer vector
# index arg must be character
# if names arg is NULL, use colnames(object)
check.character.index <- function(index, index.name, object, names, len,
is.fixed, allow.empty, is.degree.spec)
{
stopifnot(is.character(index))
is.fixed <- check.boolean(is.fixed)
# certain regular expressions match everything, even if names not avail
if(!is.fixed && length(index) == 1 && index %in% c("", ".", ".*"))
return(1:len)
if(is.null(names))
names <- colnames(object)
if(length(names) == 0 || !is.character(names))
stop0(index.name,
" specifies names but the names are unavailable")
matches <- integer(0)
warning.names <- integer(0) # these regexs don't match any column names
for(i in seq_along(index)) {
name <- index[i]
if(!is.fixed) # regex match
igrep <- grep(name, names)
else { # exact match
if(nchar(name) == 0)
warning0(unquote(index.name), "[", i, "] is an empty string \"\"")
igrep <- which(name == names)
}
if(length(igrep))
matches <- c(matches, igrep)
else
warning.names <- c(warning.names, name)
}
if(is.degree.spec) {
if(is.null(dim(object))) # vector, degree1
matches <- matchmult(matches, object)
else if(length(dim(object)) == 2) # 2D matrix, degree2
matches <- c(matchmult(matches, object[,1]), matchmult(matches, object[,2]))
else
stop0("that kind of object is not yet supported for ", index.name)
}
new.index <- unique(matches[!is.na(matches)])
for(name in warning.names)
warning0("\"", name, "\" in ", unquote(index.name),
" does not ", if(is.fixed) "" else "regex-",
"match any names\n",
" Available names are ", paste.trunc(quotify(names)))
new.index
}
check.logical.index <- function(index, index.name, len, allow.empty)
{
stopifnot(is.logical(index))
if(!allow.empty) {
if(length(index) == 0)
stop0("length(", unquote(index.name), ") == 0")
if(length(index[index == TRUE]) == 0)
stop0(index.name, " is all FALSE")
}
# note that a single FALSE or TRUE is ok regardless of length(object)
if(length(index) > len && length(index) != 1) {
stop0("logical index ", index.name, " is too long.\n",
" Its length is ", length(index),
" and the max allowed length is ", len)
}
index
}
check.numeric.index <- function(index, index.name, len, allow.empty,
allow.negatives, allow.dups,
allow.zeros, treat.NA.as.one)
{
stopifnot(is.numeric(index))
if(!allow.empty) {
if(length(index) == 0)
stop0(index.name, " is empty, (its length is 0)")
else if(all(index == 0))
if(length(index) == 1)
stop0(index.name, " is 0")
else
stop0(index.name, " is all zeros")
}
if(!is.integral(index))
stop0(index.name, " is not an integer")
if(any(index < 0) && any(index > 0))
stop0("mixed negative and positive values in ", index.name)
if(!allow.zeros && any(index == 0) && length(index) != 1)
warning0("zero in ", index.name)
if(!allow.negatives && any(index < 0))
stop0("negative value in ", index.name)
if(!allow.dups && any(duplicated(index)))
warning0("duplicates in ", index.name)
if(any(abs(index) > len)) {
if(length(index) == 1)
prefix <- paste0(unquote(index.name), "=", index, " but ")
else
prefix <- paste0(index.name, " is out of range, ")
if(len != 1)
stop0(prefix, "allowed values are 1 to ", len)
else if(treat.NA.as.one)
stop0(prefix, "the only allowed value is 1 (or NA)")
else
stop0(prefix, "the only allowed value is 1")
}
index
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.