Manipulation of array selections
array_selection.Rd
NOTE: The tools documented in this man page are primarily intended for developers or advanced users curious about the internals of the SparseArray or DelayedArray packages. End users typically don't need them for their regular use of SparseArray or DelayedArray objects.
An array selection is just an index into an array-like object that contains the information of which array elements are selected. This index can take various forms but 3 special forms are particularly useful and extensively used in the context of the SparseArray and DelayedArray packages: linear index (also referred to as L-index or Lindex), matrix index (also referred to as M-index or Mindex), N-dimensional index (also referred to as N-index or Nindex). See Details section below for more information.
Two utility functions are provided at the moment to convert back and forth between L-indices and M-indices. More will be added in the future to convert between other types of array indices.
Usage
## Convert back and forth between L-indices and M-indices:
Lindex2Mindex(Lindex, dim, use.names=FALSE)
Mindex2Lindex(Mindex, dim, use.names=FALSE, as.integer=FALSE)
Arguments
- Lindex
An L-index. See Details section below.
- Mindex
An M-index. See Details section below.
For convenience,
Mindex
can also be specified as an integer vector with one element per dimension in the underlying array, in which case it will be treated like a 1-row matrix.- dim
An integer vector containing the dimensions of the underlying array.
Note that
dim
can also be an integer matrix, in which case it must have one row per element inLindex
(or per row inMindex
) and one column per dimension in the underlying array.- use.names
Should the names (or rownames) on the input be propagated to the output?
- as.integer
Set to
TRUE
to forceMindex2Lindex
to return the L-index as an integer vector. Dangerous!By default, i.e. when
as.integer=FALSE
,Mindex2Lindex
will return the L-index either as an integer or numeric vector. It will choose the former only if it's safe, that is, only if all the values in the L-index "fit" in the integer type. More precisely:If
dim
is not a matrix (i.e. is a vector) or if it's a matrix with a single row:Mindex2Lindex
returns an integer or numeric vector depending on whetherprod(dim)
is <=.Machine$integer.max
(2^31 - 1) or not.Otherwise
Mindex2Lindex
returns a numeric vector.
Note that with these rules,
Mindex2Lindex
can return a numeric vector even if an integer vector could have been used.Use
as.integer=TRUE
only in situations where you know that all the L-index values are going to "fit" in the integer type.Mindex2Lindex
will return garbage if they don't.
Details
The 3 special forms of array indices that are extensively used in the context of the SparseArray and DelayedArray packages:
Linear index (or L-index or Lindex): A numeric vector where each value is >= 1 and <= the length of the array-like object. When using an L-index to subset an array-like object, the returned value is a vector-like object (i.e. no dimensions) of the same length as the L-index.
Example:
Matrix index (or M-index or Mindex): An integer matrix with one column per dimension in the array-like object and one row per array element in the selection. The values in each column must be >= 1 and <= the extent of the array-like object along the corresponding dimension. When using an M-index to subset an array-like object, the returned value is a vector-like object (i.e. no dimensions) of length the number of rows in the M-index.
Example:
Note that this is the type of index returned by
base::arrayInd
.N-dimensional (or N-index or Nindex): A list with one list element per dimension in the array-like object. Each list element must be a subscript describing the selection along the corresponding dimension of the array-like object. IMPORTANT: A
NULL
subscript is interpreted as a missing subscript ("missing" like ina[ , , 1:2]
), that is, as a subscript that runs along the full extend of the corresponding dimension of the array-like object. This means that before an N-index can be used in a call to[
,[<-
,[[
or[[<-
, theNULL
list elements in it must be replaced with objects of class"name"
. When using an N-index to subset an array-like object, the returned value is another array-like object of dimensions the lengths of the selections along each dimensions.Examples:
a <- array(101:124, 4:2) ## Normalized N-index (i.e. non-NULL subscripts are integer ## vectors with positive values only): Nindex <- list(c(1, 4, 1), NULL, 1) ## Same as a[c(1, 4, 1), , 1, drop=FALSE]: S4Arrays:::subset_by_Nindex(a, Nindex) Nindex <- list(integer(0), NULL, 1) ## Same as a[integer(0), , 1, drop=FALSE]: S4Arrays:::subset_by_Nindex(a, Nindex) ## Non-normalized N-index: Nindex <- list(-3, NULL, c(TRUE, FALSE, FALSE)) Nindex <- S4Arrays:::normalize_Nindex(Nindex, a) ## Same as a[-3, , 1, drop=FALSE]: S4Arrays:::subset_by_Nindex(a, Nindex) Nindex <- list(IRanges(2, 4), NULL, 1) Nindex <- S4Arrays:::normalize_Nindex(Nindex, a) ## Same as a[2:4, , 1, drop=FALSE]: S4Arrays:::subset_by_Nindex(a, Nindex) dimnames(a)[[1]] <- LETTERS[1:4] Nindex <- list(c("D", "B"), NULL, 1) Nindex <- S4Arrays:::normalize_Nindex(Nindex, a) ## Same as a[c("D", "B"), , 1, drop=FALSE]: S4Arrays:::subset_by_Nindex(a, Nindex)
See also
arrayInd
in the base package.
Examples
## ---------------------------------------------------------------------
## M-index vs L-index
## ---------------------------------------------------------------------
a <- array(101:124, 4:2)
## The same "array selection" can be represented by an M-index or
## an L-index. Here we use both representations to select the same
## 4 array elements:
Mindex <- rbind(c(3, 2, 1),
c(2, 1, 1),
c(4, 3, 2),
c(2, 1, 1))
a[Mindex]
#> [1] 107 102 124 102
Lindex <- c(7, 2, 24, 2)
a[Lindex]
#> [1] 107 102 124 102
## Sanity check:
stopifnot(identical(a[Mindex], a[Lindex]))
## ---------------------------------------------------------------------
## Convert back and forth between M-index and L-index representation
## ---------------------------------------------------------------------
Mindex2Lindex(Mindex, dim(a)) # L-index
#> [1] 7 2 24 2
Lindex2Mindex(Lindex, dim(a)) # M-index
#> [,1] [,2] [,3]
#> [1,] 3 2 1
#> [2,] 2 1 1
#> [3,] 4 3 2
#> [4,] 2 1 1
## Sanity checks:
storage.mode(Mindex) <- storage.mode(Lindex) <- "integer"
stopifnot(identical(Mindex2Lindex(Mindex, dim(a)), Lindex))
stopifnot(identical(Lindex2Mindex(Lindex, dim(a)), Mindex))
## ---------------------------------------------------------------------
## More Mindex2Lindex() examples
## ---------------------------------------------------------------------
dim <- 4:2
Mindex2Lindex(c(4, 3, 1), dim)
#> [1] 12
Mindex2Lindex(c(4, 3, 2), dim)
#> [1] 24
Mindex <- rbind(c(1, 1, 1),
c(2, 1, 1),
c(3, 1, 1),
c(4, 1, 1),
c(1, 2, 1),
c(1, 1, 2),
c(4, 3, 2))
Mindex2Lindex(Mindex, dim)
#> [1] 1 2 3 4 5 13 24
## With a matrix of dimensions:
dims <- rbind(c(4L, 3L),
c(5L, 3L),
c(6L, 3L))
Mindex <- rbind(c(1, 2),
c(1, 2),
c(1, 2))
Mindex2Lindex(Mindex, dims)
#> [1] 5 6 7
## Sanity checks:
dim <- c(33:30, 45L, 30L)
stopifnot(Mindex2Lindex(rep(1, 6), dim) == 1)
stopifnot(Mindex2Lindex(dim, dim) == prod(dim))
stopifnot(identical(Mindex2Lindex(arrayInd(1:120, 6:4), 6:4), 1:120))
stopifnot(identical(Mindex2Lindex(arrayInd(840:1, 4:7), 4:7), 840:1))