jay.sf
jay.sf

Reputation: 72909

How to remove nothing from a matrix?

From a matrix M,

> (M <- matrix(1:9, 3, 3))
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

I want to remove/keep columns by condition and put the result into a list. There's no problem as long as the condition consists of integers without c(NA, 0), e.g.

cv1 <- 1:3
lapply(cv1, function(x) M[, -x])

For the case there's no column to remove I tried to add NA or 0 to the condition vector, but it won't work.

cv2 <- c(NA, 1:3)
cv3 <- 0:3

> lapply(cv2, function(x) M[, -x])[[1]]
[1] NA NA NA

> lapply(cv3, function(x) M[, -x])[[1]]

[1,]
[2,]
[3,]

I know I can do

lapply(cv2, function(x) {
  if (is.na(x))
    M
  else
    M[, -x]
})

but I wonder if there's a simpler way.

Actually question:

What strikes me in the first place is that the matrix disappears instead of remaining complete in following cases, although I'm actually trying to remove nothing:

M[, -(na.omit(NA))]
M[, na.omit(-(NA))]
M[, -0]
M[, -logical(0)]

# [1,]
# [2,]
# [3,]

or

> M[, -NULL]
Error in -NULL : invalid argument to unary operator

Can somebody explain the reason and the advantage of this behavior, and/or how to say it right?

Upvotes: 1

Views: 91

Answers (1)

user2554330
user2554330

Reputation: 44877

The reason is pretty simple: the minus sign in -x isn't treated as something special, it's just a regular mathematical operation. So -0 is the same as 0, and -NA is the same as NA.

@Cettt gave one answer: setdiff(seq_len(ncol(M)), x) will give the column numbers other than x. You can do the same sort of thing using logical indexing as seq_len(ncol(M)) != x will work if x is a number, but not if x is NA. If you really need to handle that case too, you could use is.na(x) | seq_len(ncol(M)) != x, but @Cettt's solution looks simpler.

Upvotes: 1

Related Questions