1
votes

Ajouter un index de position à une liste

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


4 commentaires

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!


6 Réponses :


2
votes
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

2 commentaires

Cela changerait-il les noms?


@Denis, ça ne devrait pas



1
votes

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


0 commentaires

2
votes

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)


0 commentaires

1
votes

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


0 commentaires

2
votes

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


1 commentaires

La Map semble idéale pour cela. Vous pouvez également réduire cela davantage - Map (c, lst, e3 = seq_along (lst))



1
votes

Nous pouvons également utiliser une boucle for

for(i in seq_along(lst)) lst[[i]]$e3 <- i


0 commentaires