How to Rename Element's List Indexed by a Loop in R

How can I rename the elements of the list within another list using for loop?

When working with lists, it's often useful to map functions over them rather than using loops. For this case, you can use an indexed map to modify the names of each sub-list element according to the index of its parent list:

library(purrr)

renamed_list <- imap(list, function(l, n) {names(l) <- paste0(names(l), n) ; l})

str(renamed_list)

#> List of 2
#> $ :List of 2
#> ..$ x1:'data.frame': 2 obs. of 2 variables:
#> .. ..$ a: num [1:2] 1 2
#> .. ..$ b: num [1:2] 3 4
#> ..$ y1:'data.frame': 2 obs. of 3 variables:
#> .. ..$ a: num [1:2] 1 2
#> .. ..$ b: num [1:2] 3 4
#> .. ..$ c: num [1:2] 5 6
#> $ :List of 2
#> ..$ x2:'data.frame': 2 obs. of 2 variables:
#> .. ..$ a: num [1:2] 7 8
#> .. ..$ b: num [1:2] 9 10
#> ..$ y2:'data.frame': 2 obs. of 4 variables:
#> .. ..$ a: num [1:2] 11 12
#> .. ..$ b: num [1:2] 13 14
#> .. ..$ c: num [1:2] 15 16
#> .. ..$ d: num [1:2] 17 18

There's a bit to unpack in the imap line, so I'll go through it. imap takes a list (in this case your list <- list(fir, sec)) and the names or indices of its elements, and applies some function to each element that utilizes the names/indices.

I condensed it down to one line above, but the function I'm applying to each list is:

function(l, n) {
names(l) <- paste0(names(l), n)
return(l)
}

l is a sub-list, and n is the name (if named) or index (if not named) of the parent list. We take the names of our sub-list and append the name/index to whatever was already there. In this case, the parent lists don't have named elements, so we append the index and get sub-lists with elements named x1, y1, x2, y2, and so on.

Change name of element names in loop through lists

Try this:

a <- list(1, 2)
b <- list(3, 4)

for (my.list in c("a", "b")) {
x <- get(my.list)
names(x) <- c("element1", "element2")
assign(my.list, x)
}

Function for renaming specific elements of list

Modified function:

renamefct <- function(element_names, element) {
for(i in element_names) {
names(element[[i]]$namednum) <- c("Var1", "Var2", "Var3", "Var4")
}
return(element)
}

This works:

mylist <- renamefct(element_names1, mylist)

names(mylist[["type_1"]]$namednum)
[1] "Var1" "Var2" "Var3" "Var4"

Rename by list() variable name rather than index in R

Don't define x.list, just iterate over the names:

fit <- vector("list",3)
for ( i in c("x1","x2","x3") ) fit[[i]] <- summary(lm(frame$y ~ frame[[i]]))

Save lms instead. It's likely that you'll want more than the summary, so just save the lms:

xs     <- c("x1","x2","x3")
xs <- setNames(xs,xs)
fit_lm <- lapply(xs,function(i)lm(frame$y ~ frame[[i]]))

You can look at summary with lapply(fit_lm,summary), but also look at coefficients, with

sapply(fit_lm,`[[`,"coefficients")
# x1 x2 x3
# (Intercept) 0.1417501 0.2974165 0.25085281
# frame[[i]] 0.2318912 -0.1468433 -0.08783857

Change list items in for loop in R

for(item in myList) creates a new object called item

If you want to refer to the items from the list, it would be better to do it by calling either their position with myList[1], or their name with myList[["a"]].

You can for-loop through the list by using the index (as one of the comments suggested).

myList <- list(a=1, b=2, c=4, d=5)
for(i in 1:length(myList)){
myList[i] <- 3
}
myList

But I would recomment a vector approach. Check this out:

myList <- list(a=1, b=2, c=1, d=5)
myList=='1'
myList[myList=='1']=3
myList
myList[names(myList)=='a']=9
myList

Now you do not have any redundant variables.

This is actually the recommended approach in R. For-loops are too computationally expensive.

Name output from a for loop using a list in R

When I am moving along multiple variables, I tend to use an index (or name) instead. This should work for you:

recording_list <- recording_summary$Original_filename # chr [1:100]
clipID_list <- recording_summary$ClipID # int [1:100]

for (idx in 1:length(recording_list)){
wavIN <- readWave(recording_list[idx], from=120, to=301, units="seconds")
writeWave(wavIN, paste0(clipID_list[idx], ".wav"))
rm(wavIN)
}

Renaming dataframe column elements using a for loop

The for loop does not work because it iterates over each element of the vector and R does work "by value", not "by reference", this means, if you modify "x" R creates a new "memory slot" but does NOT modify the original vector.

Just remove the first character instead of looping over each row/element which is BTW bad practice - use a vectorized version instead that "loops" implicitly:

max.length <- max(nchar(as.character(Anscombe$set)))
Anscombe$set2 <- substr(Anscombe$set, 2, max.length) # remove first character

The result is a character type (I have not touched set so that you can see the difference):

> Anscombe
set x y set2
1 x1 10 8.04 1
5 x1 11 8.33 1
9 x1 12 10.84 1
14 x2 13 8.74 2
18 x2 6 6.13 2
22 x2 5 4.74 2
23 x3 10 7.46 3
27 x3 11 7.81 3
31 x3 12 8.15 3
36 x4 8 7.71 4
40 x4 8 5.25 4
44 x4 8 6.89 4

PS: Also note the Anscombe$set is a factor type (not a string) which uses a numeric internally, see:

> str(Anscombe)
'data.frame': 12 obs. of 4 variables:
$ set : Factor w/ 8 levels "x1","x2","x3",..: 1 1 1 2 2 2 3 3 3 4 ...
$ x : num 10 11 12 13 6 5 10 11 12 8 ...
$ y : num 8.04 8.33 10.84 8.74 6.13 ...

That's why I use convertion with as.character above...

Building a list in a loop in R - getting item names correct

It works if you don't use the append command:

mybiglist <- list()
for(i in 1:5){
a <- runif(10)
b <- rnorm(16)
c <- rbinom(8, 5, i/10)
name <- paste('item:',i,sep='')
tmp <- list(uniform=a, normal=b, binomial=c)
mybiglist[[name]] <- tmp
}

# List of 5
# $ item:1:List of 3
# ..$ uniform : num [1:10] 0.737 0.987 0.577 0.814 0.452 ...
# ..$ normal : num [1:16] -0.403 -0.104 2.147 0.32 1.713 ...
# ..$ binomial: num [1:8] 0 0 0 0 1 0 0 1
# $ item:2:List of 3
# ..$ uniform : num [1:10] 0.61 0.62 0.49 0.217 0.862 ...
# ..$ normal : num [1:16] 0.945 -0.154 -0.5 -0.729 -0.547 ...
# ..$ binomial: num [1:8] 1 2 2 0 2 1 0 2
# $ item:3:List of 3
# ..$ uniform : num [1:10] 0.66 0.094 0.432 0.634 0.949 ...
# ..$ normal : num [1:16] -0.607 0.274 -1.455 0.828 -0.73 ...
# ..$ binomial: num [1:8] 2 2 3 1 1 1 2 0
# $ item:4:List of 3
# ..$ uniform : num [1:10] 0.455 0.442 0.149 0.745 0.24 ...
# ..$ normal : num [1:16] 0.0994 -0.5332 -0.8131 -1.1847 -0.8032 ...
# ..$ binomial: num [1:8] 2 3 1 1 2 2 2 1
# $ item:5:List of 3
# ..$ uniform : num [1:10] 0.816 0.279 0.583 0.179 0.321 ...
# ..$ normal : num [1:16] -0.036 1.137 0.178 0.29 1.266 ...
# ..$ binomial: num [1:8] 3 4 3 4 4 2 2 3

Rename elements of list based on condition

Here is an option - loop over the list with map and do the changes with a condition (if/else) (Here, we are using errorlist as it is more general. It also works with samplelist)

library(dplyr)
library(purrr)
map(errorlist, ~ if(ncol(.x) == 1 && names(.x) == 'sample_0')
setNames(.x, 'sampling') else
rename_with(.x, ~ 'sampling', matches('sample_1')))

-output

$Alpha
# A tibble: 5 × 2
sample_0 sampling
<dbl> <dbl>
1 3 NA
2 NA 8
3 7 5
4 9 4
5 2 NA

$Beta
# A tibble: 5 × 2
sample_0 sampling
<dbl> <dbl>
1 2 3
2 9 7
3 NA 9
4 3 3
5 7 NA

$Gamma
# A tibble: 5 × 1
sampling
<dbl>
1 NA
2 NA
3 4
4 6
5 3

$Delta
# A tibble: 5 × 1
error
<dbl>
1 3
2 7
3 9
4 3
5 NA


Update

Based on the OP's comments

lapply(errorlist, \(x) {
nm1 <- stringr::str_subset(names(x), "^sample_\\d+$")
i1 <- which.max(as.numeric(stringr::str_extract(nm1,
"(?<=sample_)\\d+")))
if(length(i1) > 0) names(x)[names(x) == nm1[i1]] <- "sampling"
x})

-output

$Alpha
# A tibble: 5 × 3
sample_0 sample_1 sampling
<dbl> <dbl> <dbl>
1 3 NA 7
2 NA 8 3
3 7 5 5
4 9 4 NA
5 2 NA NA

$Beta
# A tibble: 5 × 3
sample_0 sample_1 sampling
<dbl> <dbl> <dbl>
1 2 3 4
2 9 7 2
3 NA 9 6
4 3 3 4
5 7 NA 6

$Gamma
# A tibble: 5 × 2
sample_0 sampling
<dbl> <dbl>
1 NA 3
2 NA 7
3 4 3
4 6 NA
5 3 8

$Delta
# A tibble: 5 × 1
error
<dbl>
1 3
2 7
3 9
4 3
5 NA


Related Topics



Leave a reply



Submit