Domanda

Potrei risolverlo usando i loop, ma sto provando a pensare in vettori, quindi il mio codice sarà più R-esque.

Ho una lista di nomi.Il formato è nome_cognome.Voglio ottenere da questo elenco un elenco separato con solo i nomi.Non riesco a capire come farlo.Ecco alcuni dati di esempio:

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

che assomiglia a questo:

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

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

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

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

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

Potrei ottenere quello che voglio usando loop come questo:

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

che mi darebbe questo:

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

Allora come posso farlo senza loop?

È stato utile?

Soluzione

È possibile utilizzare apply (o 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" 

Si veda: Una breve introduzione “applicare” in R

Altri suggerimenti

E un approccio più:

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

In parole, l'ultima riga estrae il primo elemento di ciascun componente della lista e quindi semplifica in un vettore.

Come funziona? Ebbene, è necessario rendersi conto un modo alternativo di scrivere x[1] è "["(x, 1), vale a dire non v'è una funzione chiamata [ che fa sottoinsiemi. La chiamata sapply applica chiamate questa funzione una volta per ogni elemento della lista originale, passando due argomenti, l'elemento della lista e 1.

Il vantaggio di questo approccio rispetto agli altri è che è possibile estrarre più elementi dalla lista, senza dover ricalcolare le spaccature. Ad esempio, il cognome sarebbe sapply(pieces, "[", 2). Una volta che ci si abitua a questo idioma, è abbastanza facile da leggere.

Come su:

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

per l'approccio RegEx?

che dire:

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

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

Dubito che questa è la soluzione più elegante, ma batte loop:

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

La conversione di liste per i frame di dati è l'unico modo in cui posso ottenere loro di fare quello che voglio. Non vedo l'ora di leggere le risposte da parte di persone che effettivamente capire come gestire le liste.

Ce l'avevi quasi fatta.Esso Veramente è solo questione di

  1. utilizzando uno dei *apply funzioni per ripetere l'elenco esistente, spesso inizio con lapply e talvolta passare a sapply
  2. aggiungi una funzione anonima che opera su uno degli elementi della lista alla volta
  3. sapevi già che lo era strsplit(string, splitterm) e che hai bisogno della dispari [[1]][1] per eliminare il primo termine della risposta
  4. basta mettere tutto insieme, iniziando con una variabile preferita namne (da cui stiamo alla larga t O c e amici)

che dà

> tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan") 
> fnames <- sapply(tlist, function(x) strsplit(x, "_")[[1]][1]) 
> fnames 
  bob_smith    mary_jane   jose_chung michael_marx charlie_ivan   
      "bob"       "mary"       "jose"    "michael"    "charlie" 
>

È possibile utilizzare unlist():

> tsplit <- unlist(strsplit(t,"_"))
> tsplit
 [1] "bob"     "smith"   "mary"    "jane"    "jose"    "chung"   "michael"
 [8] "marx"    "charlie" "ivan"   
> t_out <- tsplit[seq(1, length(tsplit), by = 2)]
> t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Ci potrebbe essere un modo migliore per tirare fuori solo le voci dispari indicizzato, ma in ogni caso non sarà necessario un ciclo.

E un altro approccio, sulla base di esempio non elencati di brentonk ...

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]

Vorrei utilizzare il seguente non elencati () - metodo basato:

> t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> tsplit <- strsplit(t,"_")
> 
> x <- matrix(unlist(tsplit), 2)
> x[1,]
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Il grande vantaggio di questo metodo è che risolve il problema equivalente dei cognomi allo stesso tempo:

> x[2,]
[1] "smith" "jane"  "chung" "marx"  "ivan" 

Lo svantaggio è che è necessario essere certi che tutti i nomi conformi alla struttura firstname_lastname; se c'è ne non questo metodo si romperà.

dalla lista tsplit oggetto originale dato all'inizio, questo comando farà:

unlist(lapply(tsplit,function(x) x[1]))

estrae il primo elemento di tutti gli elementi della lista, quindi trasforma un elenco per un vettore. Unlisting prima ad una matrice, quindi estrarre la colonna pugno è anche ok, ma poi si sono dipendenti dal fatto che tutti gli elementi dell'elenco hanno la stessa lunghezza. Ecco l'output:

> tsplit

[[1]]
[1] "bob"   "smith"

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

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

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

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

> lapply(tsplit,function(x) x[1])

[[1]]
[1] "bob"

[[2]]
[1] "mary"

[[3]]
[1] "jose"

[[4]]
[1] "michael"

[[5]]
[1] "charlie"

> unlist(lapply(tsplit,function(x) x[1]))

[1] "bob"     "mary"    "jose"    "michael" "charlie"
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top