Pergunta

Eu poderia resolver isso usando loops, mas estou tentando pensar em vetores para que meu código seja mais R-Sque.

Eu tenho uma lista de nomes. O formato é primeironame_lastname. Quero sair desta lista uma lista separada com apenas os primeiros nomes. Parece que não consigo entender como fazer isso. Aqui estão alguns dados de exemplo:

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

que se parece com o seguinte:

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

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

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

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

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

Eu poderia sair do que quero usando loops 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])} 
}

o que me daria isso:

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

Então, como posso fazer isso sem loops?

Foi útil?

Solução

Você pode usar 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" 

Ver: Uma breve introdução para "aplicar" em r

Outras dicas

E mais uma abordagem:

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

Em palavras, a última linha extrai o primeiro elemento de cada componente da lista e a simplifica em um vetor.

Como é que isso funciona? Bem, você precisa perceber uma maneira alternativa de escrever x[1] é "["(x, 1), ou seja, há uma função chamada [ Isso é subconjunto. o sapply A chamada aplica chama essa função uma vez para cada elemento da lista original, passando em dois argumentos, o elemento da lista e 1.

A vantagem dessa abordagem sobre os outros é que você pode extrair vários elementos da lista sem precisar recomputar as divisões. Por exemplo, o sobrenome seria sapply(pieces, "[", 2). Depois de se acostumar com esse idioma, é muito fácil de ler.

Que tal:

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 a abordagem regex?

A respeito:

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

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

Duvido que esta seja a solução mais elegante, mas supera o loop:

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

A conversão de listas em quadros de dados é a única maneira de fazer com que eles façam o que eu quiser. Estou ansioso para ler respostas de pessoas que realmente entendem como lidar com listas.

Você quase teve. Isto verdade é apenas uma questão de

  1. usando um dos *apply funções para dar um loop sobre sua lista existente, muitas vezes começo com lapply E às vezes muda para sapply
  2. Adicione uma função anônima que opera em um dos elementos da lista de cada vez
  3. Você já sabia que era strsplit(string, splitterm) e que você precisa do estranho [[1]][1] Para escolher o primeiro mandato da resposta
  4. Basta juntar tudo, começando com uma variável preferida Namne (como ficamos afastados t ou c e amigos)

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

Você poderia 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"

Pode haver uma maneira melhor de retirar apenas as entradas indexadas, mas, de qualquer forma, você não terá um loop.

E uma outra abordagem, com base no exemplo de Ulhist 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]

Eu usaria o seguinte método baseado em UNLIST ():

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

A grande vantagem desse método é que ele resolve o problema equivalente para sobrenomes ao mesmo tempo:

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

A desvantagem é que você precisará ter certeza de que todos os nomes estão em conformidade com o firstname_lastname estrutura; Se houver, não, esse método quebrará.

do original tsplit Objeto de lista fornecida no início, este comando fará:

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

Ele extrai o primeiro elemento de todos os elementos da lista e transforma uma lista em um vetor. Unistar primeiro a uma matriz e, em seguida, extrair a coluna do punho também é bom, mas você depende do fato de que todos os elementos da lista têm o mesmo comprimento. Aqui está a saída:

> 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top