Denis
Denis

Reputation: 12077

Add positional index to a list

I would like to add a sequential element onto a list. Suppose I have the following list

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

I would like to append a e3 which is the position index of that element in the list so essentially I would like my list to be:

$A
$A$e1
[1] "a"

$A$e2
[1] "!"

$A$e3
[1] 1

$B
$B$e1
[1] "b"

$B$e2
[1] "@"

$B$e3
[1] 2

Upvotes: 2

Views: 72

Answers (6)

akrun
akrun

Reputation: 887118

We can use a for loop as well

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

Upvotes: 1

markus
markus

Reputation: 26343

Another option using Map

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

This could be written even more concise as

Map(c, lst, e3 = seq_along(lst))

Thanks to @thelatemail

Upvotes: 2

dipetkov
dipetkov

Reputation: 3700

Here is a solution that doesn't assume that the sub-lists have the same known number of elements.

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)

Created on 2019-03-06 by the reprex package (v0.2.1)

Upvotes: 2

d.b
d.b

Reputation: 32548

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

Upvotes: 2

divibisan
divibisan

Reputation: 12155

We can loop along the length of lst with lapply, adding this sequential index to each element.

lst2 <- lapply(seq_along(lst), function(i) {
    df <- lst[[i]]
    df$e3 <- i
    return(df)
})
names(lst2) <- names(lst) # Preserve names from lst

Or, if you're not scared about modifying in place:

lapply(seq_along(lst), function(i) {
    lst[[i]]$e3 <<- i
})

Both give the same output:

$A
$A$e1
[1] "a"
$A$e2
[1] "!"
$A$e3
[1] 1


$B
$B$e1
[1] "b"
$B$e2
[1] "@"
$B$e3
[1] 2

Upvotes: 1

Michael Scott
Michael Scott

Reputation: 186

Assuming I understood correctly, that you want to add a 3rd element to each nested list which contains the index of that list in it's parent list. This works:

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

Upvotes: 1

Related Questions