Passing Empty Index in R

Passing empty index in R

The index argument in subsetting is allowed to be "missing" (see ?"["):

ff1 = function(x, i) x[i] 
ff2 = function(x, i = TRUE) x[i]
ff3 = function(x, i = seq_along(x)) x[i]
ff4 = function(x, i = substitute()) x[i]

a = sample(10)
a
# [1] 3 8 2 6 9 7 5 1 4 10
ff1(a)
# [1] 3 8 2 6 9 7 5 1 4 10
ff2(a)
# [1] 3 8 2 6 9 7 5 1 4 10
ff3(a)
# [1] 3 8 2 6 9 7 5 1 4 10
ff4(a)
# [1] 3 8 2 6 9 7 5 1 4 10

a = runif(1e6)
identical(ff1(a), ff2(a))
#[1] TRUE
identical(ff1(a), ff3(a))
#[1] TRUE
identical(ff1(a), ff4(a))
#[1] TRUE
microbenchmark::microbenchmark(ff1(a), ff2(a), ff3(a), ff4(a), times = 25)
#Unit: milliseconds
# expr min lq median uq max neval
# ff1(a) 2.026772 2.131173 2.207037 2.930885 3.789409 25
# ff2(a) 12.091727 12.151931 12.318625 12.740057 16.829445 25
# ff3(a) 8.930464 9.104118 9.454557 9.643175 13.131213 25
# ff4(a) 2.024684 2.090108 2.156577 2.289166 3.496391 25

Pass empty argument as array index

You can use missing, so that a missing index implies "select all", which I assume means that the user would just want the grand mean.

myfun <- function(index)
{
if(missing(index)) mean(data) else apply(data[, index, ], 1:2, mean)
}

Indexing a list with an empty index

In short l[] will return the whole list.

(l <- list(a = 1, b = 2))
l[]

l[] <- list(c=3) is essentially reassigning what was assigned to each index to now be the result of list(c=3). For this example, it is the same as saying l[[1]] <- 3 and l[[2]] <- 3. From the ?'[' page, which mentions empty indexing a few times:

When an index expression appears on the left side of an assignment (known as subassignment) then that part of x is set to the value of the right hand side of the assignment.

and also

An empty index selects all values: this is most often used to replace all the entries but keep the attributes.

So, I roughly take this to mean each index of l should evaluate to list(c=3).

When you enter (l[] <- list(c = 3)) what is being returned is the replacement value. When you then enter l or l[] you will see that the values at each index have been replaced by list(c=3).

R drop by empty index on vector inconsistent behaviour

This doesn't work because which(d > 100) and -which(d > 100) are the same object: there is no difference between an empty vector and the negative of that empty vector.

For example, imagine you did:

d = 1:10

indexer = which(d > 100)
negative_indexer = -indexer

The two variables would be the same (which is the only consistent behavior- turning all the elements of an empty vector negative leaves it the same since it has no elements).

indexer
#> integer(0)
negative_indexer
#> integer(0)
identical(indexer, negative_indexer)
#> [1] TRUE

At that point, you couldn't expect d[indexer] and d[negative_indexer] to give different results. There is also no place to provide an error or warning: it doesn't know when passed an empty vector that you "meant" the negative version of that empty vector.


The solution is that for subsetting there's no reason you need which() at all: you could use d[d > 10] instead of your original example. You could therefore use !(d > 100) or d <= 100 for your negative indexing. This behaves as you'd expect because d > 10 or !(d > 100) are logical vectors rather than vectors of indices.

Subsetting vector: how to programatically pass negative index safely?

You could use an if() statement inside the brackets. For example, this will just return the whole vector if n is zero and remove the sequence 1:n otherwise.

x <- 1:10

n <- 0
x[ if(n == 0) TRUE else -seq_len(n) ] ## n == 0 is !n for the golfers
# [1] 1 2 3 4 5 6 7 8 9 10

n <- 5
x[ if(n == 0) TRUE else -seq_len(n) ]
# [1] 6 7 8 9 10

Complement of empty index vector is empty index vector

Maybe use;

x <- c(1, 2, 3)
y <- c(4, 5, 6)
y[!y<x]
> y[!y<x]
[1] 4 5 6

x <- c(1, 2, 3)
y <- c(4, 1, 6)
> y[!y<x]
[1] 4 6
>

How to pass nothing as an argument to `[` for subsetting?

After some poking around, alist seems to do the trick:

x <- matrix(1:6, nrow=3)
x
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6

# 1st row
do.call(`[`, alist(x, 1, ))
[1] 1 4

# 2nd column
do.call(`[`, alist(x, , 2))
[1] 4 5 6

From ?alist:

‘alist’ handles its arguments as if they described function
arguments. So the values are not evaluated, and tagged arguments
with no value are allowed whereas ‘list’ simply ignores them.
‘alist’ is most often used in conjunction with ‘formals’.


A way of dynamically selecting which dimension is extracted. To create the initial alist of the desired length, see here (Hadley, using bquote) or here (using alist).

m <- array(1:24, c(2,3,4))
ndims <- 3
a <- rep(alist(,)[1], ndims)
for(i in seq_len(ndims))
{
slice <- a
slice[[i]] <- 1
print(do.call(`[`, c(list(m), slice)))
}

[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 3 9 15 21
[3,] 5 11 17 23

[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 2 8 14 20

[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6

list indexing with [[ vs [ and NULL

Suppose we have a list as:

mylist  = list()
mylist[[1]] = c(1,2,3)
mylist[[2]] = c(4,5,6)

In the concept of list we can say mylist has two layers which can be accessed by [[ and there element can be accessed by[ like:

mylist[[1]][2]  

In your case mylist has no layer so when you do mylist[1] R defaultly access first layer and says there are no elements in the first layer of mylist and returns NULL but when you do mylist[[1]] R says Out of Bounds because the first layer of mylist has been called and there is no layer at all. That's why R throws error in [[ case.



Related Topics



Leave a reply



Submit