Je voudrais ajouter un élément séquentiel sur une liste. Supposons que j'ai la liste suivante
$A $A$e1 [1] "a" $A$e2 [1] "!" $A$e3 [1] 1 $B $B$e1 [1] "b" $B$e2 [1] "@" $B$e3 [1] 2
Je voudrais ajouter un e3 qui est l'index de position de cet élément dans la liste donc j'aimerais essentiellement que ma liste be:
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="@"))
$A
$A$e1
[1] "a"
$A$e2
[1] "!"
$B
$B$e1
[1] "b"
$B$e2
[1] "@"
6 Réponses :
setNames(lapply(seq_along(lst), function(i){
temp = lst[[i]]
temp$e3 = i
temp
}), names(lst))
#$`A`
#$`A`$`e1`
#[1] "a"
#$`A`$e2
#[1] "!"
#$`A`$e3
#[1] 1
#$B
#$B$`e1`
#[1] "b"
#$B$e2
#[1] "@"
#$B$e3
#[1] 2
Cela changerait-il les noms?
@Denis, ça ne devrait pas
En supposant que j'ai bien compris, que vous souhaitez ajouter un 3ème élément à chaque liste imbriquée qui contient l'index de cette liste dans sa liste parent. Cela fonctionne:
library(rlist)
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="@"))
for(i in seq(1:length(lst))){
lst[[i]] <- list.append(lst[[i]],e3=i)
}
lst
Voici une solution qui ne suppose pas que les sous-listes aient le même nombre d'éléments connu.
library("tidyverse")
library("glue")
lst <- list("A"=list(e1="a",e2="!"), "B"=list(e1="b", e2="@"))
# The part
# `setNames(list(.y), glue("e{length(.x) + 1}"))`
# creates a one-element list named accordingly to append to the previous list
map2(lst, seq(lst),
~ append(.x, setNames(list(.y), glue("e{length(.x) + 1}") )))
#> $A
#> $A$e1
#> [1] "a"
#>
#> $A$e2
#> [1] "!"
#>
#> $A$e3
#> [1] 1
#>
#>
#> $B
#> $B$e1
#> [1] "b"
#>
#> $B$e2
#> [1] "@"
#>
#> $B$e3
#> [1] 2
# If naming the additional element is not important, then this can simplified to
map2(lst, seq(lst), append)
# or
map2(lst, seq(lst), c)
Créé le 2019-03-06 par le package reprex (v0.2.1)
Nous pouvons faire une boucle sur la longueur de lst avec lapply , en ajoutant cet index séquentiel à chaque élément.
$A $A$e1 [1] "a" $A$e2 [1] "!" $A$e3 [1] 1 $B $B$e1 [1] "b" $B$e2 [1] "@" $B$e3 [1] 2
Ou, si vous n'avez pas peur de modifier sur place:
lapply(seq_along(lst), function(i) {
lst[[i]]$e3 <<- i
})
Les deux donnent le même résultat:
lst2 <- lapply(seq_along(lst), function(i) {
df <- lst[[i]]
df$e3 <- i
return(df)
})
names(lst2) <- names(lst) # Preserve names from lst
Une autre option utilisant Map
Map(c, lst, e3 = seq_along(lst))
Cela pourrait être écrit encore plus concis comme
Map(function(x, y) c(x, "e3" = y), x = lst, y = seq_along(lst)) #$A #$A$e1 #[1] "a" #$A$e2 #[1] "!" #$A$e3 #[1] 1 #$B #$B$e1 #[1] "b" #$B$e2 #[1] "@" #$B$e3 #[1] 2
Merci à @thelatemail
La Map semble idéale pour cela. Vous pouvez également réduire cela davantage - Map (c, lst, e3 = seq_along (lst))
Nous pouvons également utiliser une boucle for
for(i in seq_along(lst)) lst[[i]]$e3 <- i
Puis-je demander pourquoi? Cela semble causer beaucoup de confusion et de bugs si quelque chose arrive à changer l'ordre des éléments dans la liste. Si vous nous montrez le problème que cela résout, il pourrait y avoir une solution plus robuste.
C'est pour un calcul que je fais. J'aime garder mes valeurs évidentes
pour (i dans seq_along (lst)) lst [[i]] $ e3 <- i@akrun - ma réponse préférée comme toujours, simple et directe :-). Vous devriez ajouter cela comme réponse!