Home > OS >  Basic question about minus sign for negative operator
Basic question about minus sign for negative operator

Time:02-20

I am not sure I understand the behaviour of the minus sign.

x <- 10:1
y <- c(4, 7)
x[y]
# [1] 7 4
x[-y]
# [1] 10  9  8  6  5  3  2  1

So the - sign in x[-y] is understood as items of x that are not y.

x <- 10:1
y <- 1:10
x[-y]
# integer(0)

Again logical, if y has all the element of x, x[-y] should be empty.

Now if y is itself empty, you'd expect that x[-y] should list all the elements of x. However:

x <- 10:1
y <- integer()
x[-y]
# integer(0)

What is it that I am not understanding? Is there any other operator to do what I want (i.e. list the elements of x that are not in y, and thus list all elements of x is y is empty)?

CodePudding user response:

@jay.sf's answer explains how to get what you want. I just wanted to add a bit more explanation, and give a suggestion for a different approach.

When you say x[-y], the minus sign doesn't have any special meaning: it just changes the sign of the elements of y. It will give the same result as

z <- -y
x[z]

When y is empty, z will be empty as well, so x[y] is the same as x[-y].

My recommendation is to use logical indices when you want to do logical operations on them. So you might have been doing this:

y <- which(x %% 50 == 11)

to choose the entries which meet the condition x %% 50 == 11. Then if you happen to have a vector where nothing meets the condition, you get an empty y. A better approach is

y <- x %% 50 == 11

so that y is a vector of all FALSE values. If you want the complement, use

x[!y]

and you'll get all of x.

CodePudding user response:

So the - sign in x[-y] is understood as items of x that are not y.

No, y is used as indices of x here. You can think of it like this:

setNames(x, paste0('x', seq_along(x)))
#  x1  x2  x3  x4  x5  x6  x7  x8  x9 x10 
# 10   9   8   7   6   5   4   3   2   1 

x[-c(4, 7)]  ## delete x4 and x7
# [1] 10  9  8  6  5  3  2  1

If you want elements in x that are not in y you need to say:

x[!x %in% y]
# [1] 10  9  8  6  5  3  2  1

y1 <- NULL
x[!x %in% y1]
# [1] 10  9  8  7  6  5  4  3  2  1

Or:

setdiff(x, y)
# [1] 10  9  8  6  5  3  2  1

setdiff(x, y1)
# [1] 10  9  8  7  6  5  4  3  2  1

Accordingly, in this one we delete all element indices from 1:10, and since we have only 10 elements in x we get the empty vector:

x[-(1:10)]
# numeric(0)

For the last one, we may read in documetation help("Extract"), that "an empty index selects all values: this is most often used to replace all the entries but keep the attributes."

x[-integer()]
# integer(0)

How to delete nothing

If we want to delete nothing, we need an index that is higher than the number of elements in x,

x[-11]
# [1] 10  9  8  7  6  5  4  3  2  1

where we could do dynamically:

x[-.Machine$integer.max]
# [1] 10  9  8  7  6  5  4  3  2  1
  • Related