27 votes

Comment éviter une boucle en R : sélection d'éléments dans une liste

Je pourrais résoudre ce problème en utilisant des boucles, mais j'essaie de penser en vecteurs, donc mon code sera plus R-esque.

J'ai une liste de noms. Le format est Prénom_Nom de famille. Je veux extraire de cette liste une liste distincte contenant uniquement les prénoms. Je ne parviens pas à comprendre comment faire. Voici quelques exemples de données :

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- strsplit(t,"_")

qui ressemble à ceci :

> tsplit
[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

Je pourrais obtenir ce que je veux en utilisant des boucles comme celle-ci :

for (i in 1:length(tsplit)){
    if (i==1) {t_out <- tsplit[[i]][1]} else{t_out <- append(t_out, tsplit[[i]][1])} 
}

ce qui me donnerait ça :

t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Alors comment puis-je faire cela sans boucles ?

41voto

hadley Points 33766

Et une autre approche :

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)

En d'autres termes, la dernière ligne extrait le premier élément de chaque composante de la liste, puis la simplifie en un vecteur.

Comment cela fonctionne-t-il ? Eh bien, vous devez réaliser une autre façon d'écrire x[1] es "["(x, 1) c'est-à-dire qu'il existe une fonction appelée [ qui fait le sous-ensemble. Le site sapply call appelle cette fonction une fois pour chaque élément de la liste originale, en passant deux arguments, l'élément de la liste et 1.

L'avantage de cette approche par rapport aux autres est que vous pouvez extraire plusieurs éléments de la liste sans avoir à recalculer les divisions. Par exemple, le nom de famille serait sapply(pieces, "[", 2) . Une fois que vous vous êtes habitué à cet idiome, il est assez facile à lire.

24voto

liebke Points 286

Vous pouvez utiliser apply (ou sapply )

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
f <- function(s) strsplit(s, "_")[[1]][1]
sapply(t, f)

bob_smith    mary_jane   jose_chung michael_marx charlie_ivan 

       "bob"       "mary"       "jose"    "michael"    "charlie" 

Voir : Une brève introduction à "apply" dans R

9voto

William Doane Points 690

Pourquoi pas :

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
fnames <- gsub("(_.*)$", "", tlist)
# _.* matches the underscore followed by a string of characters
# the $ anchors the search at the end of the input string
# so, underscore followed by a string of characters followed by the end of the input string

pour l'approche RegEx ?

9voto

Karsten Points 81

De quoi :

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")

sub("_.*", "", t)

7voto

Matt Parker Points 7373

Je doute que ce soit la solution la plus élégante, mais c'est mieux que de faire des boucles :

t.df <- data.frame(tsplit)
t.df[1, ]

Convertir des listes en cadres de données est à peu près le seul moyen de leur faire faire ce que je veux. J'ai hâte de lire les réponses des personnes qui savent réellement comment manipuler les listes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X