Search code examples
rsubsetslice

Slice/subset in R using vector/matrix/list as indices


We can get element at 2nd row, 4th column as

iris[2,4]

How to do the same if I have a vector/matrix of the slicing elements. ie can i get any of the following to give the same output as iris[2,4] ? (Or anything similar, without creating any temporary variables)

a = c(2,4)
b = matrix(c(2,4), nrow=1)
c = list(2,4)
iris[a]
iris[b]
iris[c]

Solution

  • The value is coerced to character because you're using a matrix method for subsetting, and one of the columns is of class character.

    We can circumvent this in two ways. Either we remove the character column beforehand,

    v <- c(2, 4)
    m <- matrix(c(2, 4), nrow=1)
    l <- list(2, 4)
    
    iris[,-5][t(v)]
    # [1] 0.2
    iris[,-5][m]
    # [1] 0.2
    iris[,-5][do.call(cbind, l)]
    # [1] 0.2
    

    or we use a list method for subsetting. (iris is a data.frame, so both are applicable)

    iris[[rev(v)]]
    # [1] 0.2
    iris[[rev(c(m))]]
    # [1] 0.2
    iris[[rev(unlist(l))]]
    # [1] 0.2
    

    I know it's been years, but I just wanted to reiterate that rev() is necessary when using the output from match(, arr.ind=TRUE)

    mat <- matrix(c(1:9, 1:7), 4)
    (dtf <- as.data.frame(mat))
    #   V1 V2 V3 V4
    # 1  1  5  9  4
    # 2  2  6  1  5
    # 3  3  7  2  6
    # 4  4  8  3  7
    
    (id <- which(mat == 8, arr.ind=TRUE))
    #      row col
    # [1,]   4   2
    
    mat[id]
    # [1] 8
    
    dtf[[rev(id)]] # Traverse as list; first column, then row
    # [1] 8
    
    dtf[id] # Indexing as matrix; first row, then column
    # [1] 8
    
    dtf[[id]] # Does not work
    # Error in as.matrix(x)[[i]] : 
    #   attempt to select more than one element in vectorIndex
    
    dtf[[c(id)]] # Wrong index
    # [1] 5
    
    
    ### Multiple matches
    (id <- which(mat == 2, arr.ind=TRUE))
    #      row col
    # [1,]   2   1
    # [2,]   3   3
    
    mat[id]
    # [1] 2 2
    
    dtf[id]
    # [1] 2 2
    
    dtf[[rev(id)]] # Does not work any more
    # Error in .subset2(x, i, exact = exact) : 
    #   recursive indexing failed at level 2
    
    
    ### Why traversing a data.frame as list can be useful
    (dtf$V1 <- as.character(dtf$V1))
    # [1] "1" "2" "3" "4"
    
    (id <- which(dtf == 1, arr.ind=TRUE)) # Will match both characters and numerics
    #      row col
    # [1,]   1   1
    # [2,]   2   3
    
    dtf[id] # Returns both as character
    # [1] "1" "1"
    
    l <- lapply(data.frame(t(id)), 
      function(x) {
          dtf[[rev(x)]]
      }
    )
    sapply(l, class) # Retains classes
    #          X1          X2 
    # "character"   "integer"