Existe-t-il une fonction R pour trouver l'indice d'un élément dans un vecteur?


324

Dans R, j'ai un élément xet un vecteur v. Je veux trouver le premier index d'un élément vqui est égal à x. Je sais qu'une façon de procéder est:, which(x == v)[[1]]mais cela semble excessivement inefficace. Existe-t-il un moyen plus direct de le faire?

Pour les points bonus, existe-t-il une fonction qui fonctionne si xc'est un vecteur? Autrement dit, il devrait retourner un vecteur d'indices indiquant la position de chaque élément de xin v.


Comme R est optimisé pour fonctionner avec des vecteurs, il which(x == v)[[1]]n'est pas très inefficace. C'est un ==opérateur de comparaison ( ) appliqué à tous les éléments vectoriels et un sous-ensemble sur les indices ( which). C'est tout. Rien de pertinent, tant que vous n'exécutez pas 10 000 répétitions sur cette fonction. D'autres solutions telles que matchet Positionpeuvent ne pas renvoyer autant de données que which, mais elles ne sont pas nécessairement plus efficaces.
BurninLeo

2
Ma question précisait que je préférerais une fonction vectorisée sur x, et which(x == v)[[1]]non.
Ryan C. Thompson,

Réponses:


461

La fonction matchfonctionne sur des vecteurs:

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

matchrenvoie uniquement la première rencontre d'un match, comme vous l'avez demandé. Il renvoie la position dans le deuxième argument des valeurs dans le premier argument.

Pour la correspondance multiple, %in%c'est la voie à suivre:

x <- sample(1:4,10,replace=TRUE)
x
# [1] 3 4 3 3 2 3 1 1 2 2
which(x %in% c(2,4))
# [1]  2  5  9 10

%in%renvoie un vecteur logique tant que le premier argument, avec un TRUEsi cette valeur peut être trouvée dans le deuxième argument et un FALSEsinon.


Je pense qu'un exemple avec c (2,3,3) et c (1,2,3,4) avec à la fois correspondance et% en% serait plus instructif avec moins de changements entre les exemples. match (c (2,3,3), c (1: 4)) renvoie des résultats différents à partir desquels (c (2,3,3)% en% c (1: 4)) sans avoir besoin d'un premier vecteur plus long et comme de nombreux changements d'exemple en exemple. Il convient également de noter qu'ils traitent les non-correspondances très différemment.
John

1
@John: c'est vrai, mais ce n'est pas ce que le PO a demandé. Le PO a demandé, à partir d'un long vecteur, de trouver la première correspondance d'éléments donnée dans un autre. Et pour être complet, j'ai ajouté que si vous êtes intéressé par tous les indices, vous devrez utiliser lesquels (% en%). BTW, il n'y a aucune raison de supprimer votre réponse. Ce sont des informations valides.
Joris Meys

1
Je pense qu'il serait utile de souligner que l'ordre des arguments en la matchmatière si vous voulez l'index de la première occurrence. Pour votre exemple, match(x,c(4,8))donne des résultats différents, ce qui n'est pas super évident au premier abord.
apitsch

@goldenoslik Cela aide si vous lisez la page d'aide de match. Tout est expliqué ici. Mais j'ai ajouté cette information.
Joris Meys

Merci! Cette solution m'a sauvé la journée!
Jinhua Wang

26

la fonction Positiondans funprog {base} fait également le travail. Il vous permet de passer une fonction arbitraire et renvoie la première ou la dernière correspondance.

Position(f, x, right = FALSE, nomatch = NA_integer)


10

Une petite note sur l'efficacité des méthodes susmentionnées:

 library(microbenchmark)

  microbenchmark(
    which("Feb" == month.abb)[[1]],
    which(month.abb %in% "Feb"))

  Unit: nanoseconds
   min     lq    mean median     uq  max neval
   891  979.0 1098.00   1031 1135.5 3693   100
   1052 1175.5 1339.74   1235 1390.0 7399  100

Donc, le meilleur est

    which("Feb" == month.abb)[[1]]

Votre référence est basée sur un vecteur de longueur 12 et n'est donc pas significative. Dans votre exemple, which("Feb" == month.abb)retourne également - 2pourquoi le [[1]]?
Markus

@markus ce code qui ("Feb" == month.abb) [[1]] renvoie "2", et ce code qui (month.abb% en% "Feb") renvoie également "2". De plus, on ne sait pas pourquoi l'utilisation du vecteur n'a pas de sens
Andrii

1
Il ne s'agit pas du vecteur, mais de sa longueur. Vous devez générer un vecteur de longueur appropriée, puis faire un benchmark basé sur cela. Je cite OPs question « Je sais que d' une façon de le faire est: which(x == v)[[1]] , mais qui semble trop inefficace. »
Markus

-5

R a surchargé l' ==opérateur double égal avec une méthode de recherche de l'indice d'une aiguille dans une botte de foin vectorielle. Il donne un logicalvecteur contenant des TRUEvaleurs pour chaque correspondance dans la botte de foin.

Exemple:

haystack <- c(1, 2, 4, 3, 4)
needle <- 4
indices <- needle == haystack
indices
[1] 3  5
haystack[indices]
[1] 4  4

Cela fonctionne si les deux sont des vecteurs et peut être étendu pour utiliser plusieurs vecteurs également.


2
L' ==opérateur a déjà été mentionné dans ma question comme une solution inefficace qui ne fonctionne pas avec un vecteur d'aiguilles.
Ryan C. Thompson,

"ça marche si les deux sont des vecteurs" - peut-être, selon ce que vous voulez dire ... mais pas dans le sens voulu par l'OP.
Frank

30
Je reçois à la FALSE FALSE TRUE FALSE TRUEplace des indices dans cet exemple
Sashko Lykhenko

6
Vous n'avez jamais exécuté cela dans R. ==renvoie un vecteur logique, pas des indices. Pour cela, vous avez besoin which(), comme je l'ai expliqué il y a 7 ans.
Joris Meys
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.