I want an easy way to access the last values of objects. I have implemented a function that allows for Python-like negative indexing (count-backwards-and-keep-only-those-elements instead of R's remove-those-elements-and-keep-all-other-elements). There are some questions about this, but no one attempted to do this:
- How to access the last value in a vector?
- Getting the last n elements of a vector. Is there a better way than using the length() function?
Basically, I want to redefine [ and [[, so that one can user a special operator (e.g. _) to use Python-like indexing. For instance, like this:
iris[1, ] #first row
iris[-1, ] #everything but first row
iris[_1, ] #last row, equivalent to tail(iris, 1)
iris[, _1] #last column, equivalent to iris[ncol(iris)]
Is it possible? I know it is possible to redefine e.g. + to introduce character concatenation like other languages have (see this answer).
In case it's not possible, here's my workaround function:
extract_last = function(x, margin_1, margin_2, drop = FALSE) {
#check types
if (!(is.vector(x) || is.matrix(x) || is.data.frame(x))) stop("x was an unsupported type (not a vector, matrix or data.frame)!")
#vector
if (is.vector(x)) return(rev(x)[margin_1])
#get dims
x_dims = dim(x)
#make indices
if (missing("margin_1")) {
margin_1 = 1:x_dims[1]
} else {
margin_1 = (x_dims[1] + 1) - margin_1
}
if (missing("margin_2")) {
margin_2 = 1:x_dims[2]
} else {
margin_2 = (x_dims[2] + 1) - margin_2
}
#subset
return(x[margin_1, margin_2, drop = drop])
}
#tests
extract_last(iris, 1) == tail(iris, 1)
extract_last(iris, 10:1) == tail(iris, 10)
extract_last(iris, , 1) == iris[5]
extract_last(iris, , 2:1) == iris[4:5]
extract_last(iris, 10:1, 1) == iris[141:150, 5, drop = FALSE]
iris[nrow(iris), ]oriris[, ncol(iris)]too much typing?[methods for the implicit classes (character,numeric, ...).T <- function(...){a <- list(...); do.call(tail,a)}.. this is pretty short and does your stuff:a <- matrix(1:9,3,3); T(a[1,],1); T(a,1).`[`. So something like`[` <- function(x,y,z=NULL){if (!is.null(z)){print("this was a bad idea")} else {do.call(.Primitive("["),list(x,y))}}; b <- 1:10; b[3]; b[2,3]. [And in case you can't figure it out, userm(`[`)to get rid of it again.]Radded a keyword like, say, "last" so thatfoo[1:(last-5)]would skip the last 5 elements, but in the long run it's really not that hard to usencolornrowas Roman suggested. If you're going to be accessing the same array a lot, just define a couple variablesnrowmat <- nrow(mat)and use them.