25

Suppose I have the following vector:

x <- c(8, 6, 9, 9, 7, 3, 2, 5, 5, 1, 6, 8, 5, 2, 9, 3, 5, 10, 8, 2)

How can I find which elements are either 8 or 9?

Jaap
  • 81,064
  • 34
  • 182
  • 193
Christopher DuBois
  • 42,350
  • 23
  • 71
  • 93
  • If you meant "detect all duplicated elements". R has a useful fn `duplicated`, and you can get all duplicates with duplicated(x) | duplicated(x, fromLast=T) – smci Aug 17 '18 at 00:17

7 Answers7

42

This is one way to do it. First I get the indices at which x is either 8 or 9. Then we can verify that at those indices, x is indeed 8 and 9.

> inds <- which(x %in% c(8,9))
> inds
[1]  1  3  4 12 15 19
> x[inds]
[1] 8 9 9 8 9 8
Christopher DuBois
  • 42,350
  • 23
  • 71
  • 93
  • 2
    But suppose I'm looking for the specific indexes of two values without their orders sorted. How would I get a result of "26, 1" instead of "1, 26" if I'm looking for the indexes of Z and A in the alphabet? _which( letters %in% c( 'z', 'a' ) )_ – dasf Sep 17 '17 at 17:40
  • @dasf use any kind of sort, like bubblesort – Lumin Jan 25 '19 at 14:54
  • This should be the upvoted answer... – Union find May 08 '22 at 19:13
11

You could try the | operator for short conditions

which(x == 8 | x == 9)
David Arenburg
  • 91,361
  • 17
  • 137
  • 196
2

In this specific case you could also use grep:

# option 1
grep('[89]',x)
# option 2
grep('8|9',x)

which both give:

[1]  1  3  4 12 15 19

When you also want to detect number with more than one digit, the second option is preferred:

> grep('10|8',x)
[1]  1 12 18 19

However, I did put emphasis on this specific case at the start of my answer for a reason. As @DavidArenburg mentioned, this could lead to unintended results. Using for example grep('1|8',x) will detect both 1 and 10:

> grep('1|8',x)
[1]  1 10 12 18 19

In order to avoid that side-effect, you will have to wrap the numbers to be detected in word-bounderies:

> grep('\\b1\\b|8',x)
[1]  1 10 12 19

Now, the 10 isn't detected.

Jaap
  • 81,064
  • 34
  • 182
  • 193
2

Here is a generalized solution to find the locations of all target values (only works for vectors and 1-dimensional arrays).

locate <- function(x, targets) {
    results <- lapply(targets, function(target) which(x == target))
    names(results) <- targets
    results
}

This function returns a list because each target may have any number of matches, including zero. The list is sorted (and named) in the original order of the targets.

Here is an example in use:

sequence <- c(1:10, 1:10)

locate(sequence, c(2,9))
$`2`
[1]  2 12

$`9`
[1]  9 19
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
user3474009
  • 311
  • 1
  • 4
1

Alternatively, if you do not need to use the indices but just the elements you can do

> x <- sample(1:10,20,replace=TRUE)
> x
 [1]  6  4  7  2  9  3  3  5  4  7  2  1  4  9  1  6 10  4  3 10
> x[8<=x & x<=9]
[1] 9 9
Yann Abraham
  • 330
  • 3
  • 11
1

If you want to find the answer using loops, then the following script will do the job:

> req_nos<- c(8,9)
> pos<-list()
> for (i in 1:length(req_nos)){
  pos[[i]]<-which(x==req_nos[i])}

The output will look like this:

>pos
[[1]]
[1] 1 12 19
[[2]] 
[1] 3  4 15

Here, pos[[1]] contains positions of 8 and pos[[2]] contains positions of 9. If you are using the %in% method and change the input order of elements, i.e, c(9,8) instead of c(8,9), the output will be the same for both of them. This method alleviates such problem.

Debjyoti
  • 177
  • 1
  • 1
  • 9
-1

grepl maybe a useful function. Note that grepl appears in versions of R 2.9.0 and later. What's handy about grepl is that it returns a logical vector of the same length as x.

grepl(8, x)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE

grepl(9, x)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
[13] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE

To arrive at your answer, you could do the following

grepl(8,x) | grepl(9,x)
Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138
andrewj
  • 2,965
  • 8
  • 36
  • 37
  • I like grepl as well, great for filtering dataframes on text strings, etc. Thanks for the OR example - I thought it would be that simple, but I kept trying `||` which is the wrong syntax. – atomicules Nov 29 '10 at 17:37
  • 4
    This is a very dangerous solution. `grepl(9, c(9, 99, 654649))` will return `TRUE` for all of these. One should be very careful with exact matches and regex. – David Arenburg Apr 09 '16 at 20:20