在一个向量中查找多个元素的所有位置

25
假设我有以下向量:
x <- c(8, 6, 9, 9, 7, 3, 2, 5, 5, 1, 6, 8, 5, 2, 9, 3, 5, 10, 8, 2)

我怎样才能找到所有值为8或9的元素?


如果你的意思是“检测所有重复元素”,R语言有一个有用的函数duplicated,你可以使用duplicated(x) | duplicated(x, fromLast=T)来获取所有重复值。 - smci
7个回答

42

以下是一种方法。首先,我们获取x等于8或9的索引。然后,我们可以验证在这些索引处,x的值确实是8和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

2
但是假设我正在寻找两个值的特定索引,而不考虑它们的排序顺序。如果我正在查找字母表中Z和A的索引,我将如何获得“26,1”的结果,而不是“1,26”的结果?which( letters %in% c( 'z', 'a' ) ) - dasf
@dasf 使用任何类型的排序算法,例如冒泡排序。 - Lumin
这应该是被点赞的答案... - Union find

11
你可以尝试使用 | 运算符来简化条件语句。
which(x == 8 | x == 9)

2
在这种特定情况下,您也可以使用grep:
# option 1
grep('[89]',x)
# option 2
grep('8|9',x)

两者都提供:

[1]  1  3  4 12 15 19

如果您想检测多位数,建议使用第二种选项:

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

然而,我在回答开始时就强调了这个特定情况的原因。正如@DavidArenburg所提到的,这可能会导致意外的结果。例如使用grep('1|8',x)将会检测到110
> grep('1|8',x)
[1]  1 10 12 18 19

为避免这种副作用,您需要将要检测的数字包含在单词边界中:
> grep('\\b1\\b|8',x)
[1]  1 10 12 19

现在,10没有被检测到。

2

这里提供了一种通用的解决方案,可以找到所有目标值的位置(仅适用于向量和一维数组)。

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

这个函数返回一个列表,因为每个目标可能有任意数量的匹配项,包括零。列表按照目标的原始顺序排序(并命名)。

下面是一个使用示例:

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

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

$`9`
[1]  9 19

很好的函数,如果它返回一个向量会更好。 - Dimitrios Zacharatos
定位 <- function(x, targets) { 结果 <- lapply(targets, function(target) which(x == target)) unlist(结果) } - Dimitrios Zacharatos

1

如果你想使用循环来找到答案,那么下面的脚本可以完成这个任务:

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

输出结果将会是这样的:
>pos
[[1]]
[1] 1 12 19
[[2]] 
[1] 3  4 15

这里,pos [[1]] 包含数字8的位置,pos [[2]] 包含数字9的位置。如果使用 %in% 方法并更改元素的输入顺序,即 c(9,8) 而不是 c(8,9),则对于两者输出将是相同的。这种方法缓解了这种问题。


1
或者,如果您不需要使用索引,仅需使用元素,则可以这样做。
> 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

-1

grepl 可能是一个有用的函数。请注意,grepl 出现在 R 2.9.0 及更高版本中。 grepl 的方便之处在于它返回与 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

要得出你的答案,你可以按照以下步骤进行。
grepl(8,x) | grepl(9,x)

我也喜欢使用 grepl,对于筛选包含特定文本的数据框非常有用。感谢您提供 OR 的示例 - 我以为很简单,但我一直尝试使用 ||,这是错误的语法。 - atomicules
4
这是一个非常危险的解决方案。grepl(9, c(9, 99, 654649)) 将会对所有这些值返回 TRUE。在使用精确匹配和正则表达式时应该非常小心。 - David Arenburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接