Pregunta

Podría resolver esto usando bucles, pero estoy intentando pensar en vectores para que mi código sea más estilo R.

Tengo una lista de nombres.El formato es nombre_apellido.Quiero sacar de esta lista una lista separada con solo los nombres.Parece que no puedo entender cómo hacer esto.A continuación se muestran algunos datos de ejemplo:

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

que se parece a esto:

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

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

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

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

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

Podría obtener lo que quiero usando bucles como este:

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

que me daría esto:

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

Entonces, ¿cómo puedo hacer esto sin bucles?

¿Fue útil?

Solución

Puede utilizar 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" 

Ver: Una breve introducción “aplicar” en I

Otros consejos

Y un enfoque más:

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

En palabras, la última línea extrae el primer elemento de cada componente de la lista y luego simplifica en un vector.

¿Cómo funciona esto? Bueno, lo que necesita para darse cuenta de una forma alternativa de escribir x[1] es "["(x, 1), es decir, hay una función llamada [ que hace de subconjuntos. La llamada sapply aplica llamadas a esta función una vez para cada elemento de la lista original, pasando en dos argumentos, el elemento de lista y 1.

La ventaja de este enfoque sobre los demás es que se puede extraer varios elementos de la lista sin tener que volver a calcular las divisiones. Por ejemplo, el último nombre sería sapply(pieces, "[", 2). Una vez que se acostumbre a este idioma, que es bastante fácil de leer.

¿Qué hay de:

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

para el enfoque de expresiones regulares?

¿qué pasa con:

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

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

Dudo que esto es la solución más elegante, pero es mejor que un bucle:

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

La conversión de las listas de tramas de datos se trata de la única manera que puedo conseguir que hagan lo que yo quiero. Estoy deseando leer respuestas de las personas que realmente entienden cómo manejar listas.

Casi lo tienes.Él en realidad es solo una cuestión de

  1. usando uno de los *apply funciones para recorrer su lista existente, a menudo comienzo con lapply y a veces cambiar a sapply
  2. agregar una función anónima que opera en uno de los elementos de la lista a la vez
  3. ya sabias que era strsplit(string, splitterm) y que necesitas lo extraño [[1]][1] para seleccionar el primer término de la respuesta
  4. simplemente júntelo todo, comenzando con un nombre de variable preferido (ya que nos mantenemos alejados de t o c y amigos)

lo que da

> 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" 
>

Se puede usar 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"

Puede haber una mejor manera de sacar sólo las entradas indexados impares, pero en cualquier caso no tendrá un bucle.

Y un otro enfoque, basado en el ejemplo no listados de 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]

Me gustaría utilizar el siguiente no listados () - Método basado:

> 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"

La gran ventaja de este método es que resuelve el problema equivalente para los apellidos al mismo tiempo:

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

El inconveniente es que tendrá que estar seguro de que todos los nombres se ajustan a la estructura firstname_lastname; si alguno no entonces este método se romperá.

de la lista tsplit objeto original dado al principio, este comando lo hará:

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

extrae el primer elemento de todos los elementos de la lista, a continuación, se transforma una lista a un vector. Unlisting primero en una matriz, entonces la extracción de la columna de puño también está bien, pero entonces dependen del hecho de que todos los elementos de la lista tienen la misma longitud. Aquí está la salida:

> 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"
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top