Building a List in a Loop in R - Getting Item Names Correct

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

Assigning value to list elements in for loop, list names depending on loop

Instead of creating 25 single lists I would suggest to put your lists into one list like so:

Note: I have set k = 2 for simplicity.

library(raster)
#> Loading required package: sp

rasterList <- list()

for (i in 1:5) {
for (j in 1:5) {
name <- paste0(i * 10, "N_0", j * 10, "E")
rasterList[[name]] <- list()
for (k in 1:2) {
raster_test <- raster(ncol = 36, nrow = 18, xmn = -1000, xmx = 1000, ymn = -100, ymx = 900)
rasterList[[name]][k] <- raster_test
}
}
}

length(rasterList)
#> [1] 25

rasterList[["10N_010E"]]
#> [[1]]
#> class : RasterLayer
#> dimensions : 18, 36, 648 (nrow, ncol, ncell)
#> resolution : 55.55556, 55.55556 (x, y)
#> extent : -1000, 1000, -100, 900 (xmin, xmax, ymin, ymax)
#> crs : NA
#>
#>
#> [[2]]
#> class : RasterLayer
#> dimensions : 18, 36, 648 (nrow, ncol, ncell)
#> resolution : 55.55556, 55.55556 (x, y)
#> extent : -1000, 1000, -100, 900 (xmin, xmax, ymin, ymax)
#> crs : NA

And if still necessary you could get your 25 lists afterwards like so:

lapply(names(rasterList), function(x) assign(paste0("rasterList_", x), rasterList[[x]], envir = .GlobalEnv))

Created on 2022-01-05 by the reprex package (v2.0.1)

Get names of list in for loop

Using some dummy data and a silly contrived example

ll <- list(A = 1:10, B = LETTERS[1:10], C = letters[1:10])

You can lapply() over the indices of the elements of ll:

out <- lapply(seq_along(ll),
function(ind, list, names) {
paste(names[ind], "=", paste(list[[ind]], collapse = ", "))
}, list = ll, names = names(ll))

R> out
[[1]]
[1] "A = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

[[2]]
[1] "B = A, B, C, D, E, F, G, H, I, J"

[[3]]
[1] "C = a, b, c, d, e, f, g, h, i, j"

or for() loop over the list:

ll2 <- vector("list", length(ll))
nams <- names(ll)
for(i in seq_along(ll)) {
ll2[[i]] <- paste(nams[i], "=", paste(ll[[i]], collapse = ", "))
}
ll2

R> ll2
[[1]]
[1] "A = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10"

[[2]]
[1] "B = A, B, C, D, E, F, G, H, I, J"

[[3]]
[1] "C = a, b, c, d, e, f, g, h, i, j"

Loop over list to assign names in R not working

The item variable loops over rowlist but doesn' modify the content of rowlist.

Try:

new_row1 <- c(402, 1, "false alarm", 0)
new_row2 <- c(403, 2, "false alarm", 0)

rowlist = list(new_row1, new_row2)

for (item in 1:length(rowlist)) {
names(rowlist[[item]]) <- c("guest_id", "sessionNum", "interactions.hitType", "n")
}

bigger_false <- NULL
for (item in rowlist) {
bigger_false <- rbind( item, bigger_false)
}
bigger_false

guest_id sessionNum interactions.hitType n
item "403" "2" "false alarm" "0"
item "402" "1" "false alarm" "0"

Create a list object in a loop in R

This seems like a good fit for lapply:

pppList <- lapply(sort(unique(OT1$month)), function(i) {
a<-OT1[OT1$month==i,]
ppp(a$longitude,a$latitude,marks=a$fTSUM,window=newW)
})

...But just to explain how to fix you for-loop:

You need to have a list to assign to. And creating one of the correct length is always a good idea for performance:

x <- sort(unique(OT1$month))
pppList <- vector('list', length(x))
for(i in x) {
a<-OT1[OT1$month==i,]
b<-ppp(a$longitude,a$latitude,marks=a$fTSUM,window=newW)
pppList[[i]] <- b
plot(b,main=i)
}

How to create a new list for each iteration of for loop in R?

This code will produce lists equal to the length of my_vector having names my_list_v1 , my_list_v2 and so on, where v1 ,v2 , .... are the elements of my_vector

for (c in my_vector){
x <- DBI:dbGetQuery(conn=con, statement=query)
filename <- x[ ,c(3)]
my_list <- paste0("my_list" ,"_", c)
l <- list()
for (i in 1:length(filename)){
y <- DBI:dbGetQuery(conn=con, statement=query2)
name <- filename[i]
tmp <- list(y)
l[[name]] <- tmp
}
assign( my_list , value = l)
}

create object with loop that subsets a list in r

I think I understand now; thank you for clarifying your question in the comments. If there's something I missed or you have any questions, please let me know.

Terminology, quickly

I believe you are interested in splitting a vector of strings into multiple shorter vectors of strings based on a pattern within each element. A list is simply a vector of vectors.

g is a vector of 20 string elements (see Data code chunk below).

is.vector(g)
#> [1] TRUE

Here's a list that only contains one vector.

str(list(g))
#> List of 1
#> $ : chr [1:20] "New AS Plate 21_AS Plate_Sample 12_50.fcs" "New AS Plate 21_AS Plate_Sample 1_100.fcs" "New AS Plate 21_AS Plate_Sample 1_25.fcs" "New AS Plate 21_AS Plate_Sample 1_250.fcs" ...

Now onto the question...

In your question, you specifically ask about using assign(). Although using assign() can be convenient, [it is usually not recommended][1]. But sometimes you gotta do what you gotta do, no shame in that. Here's how you could use it manually, on one group at a time (like you show in your question).

# Using assign() one group at a time
h <- g[grep("Sample 1_", g)]
assign(x = "sample_1_group", value = h)

It is pretty straightforward (and seemingly logical) to use assign() in a for-loop.

The first step in defining a for-loop, is defining what the loop will be "loop over." Or in other words, what will change during each iteration of the loop. In your case, we are looking for a number that defines your groups. We can define a vector of those numbers manually or programmatically.

# Define groups manually
ids <- c(12,1,10,11)
ids
#> [1] 12 1 10 11

# Pattern match groups
all_ids <- gsub(pattern = ".*Sample (\\d+).*", replacement = "\\1", x = g)
all_ids
#> [1] "12" "1" "1" "1" "1" "1" "10" "10" "10" "10" "10" "11" "11" "11" "11"
#> [16] "11" "12" "12" "12" "12"
ids <- unique(all_ids)
ids
#> [1] "12" "1" "10" "11"

After we know what we are looping over, we can define the structure of the loop and functions within in. paste0() can be a workhorse here. The loop below iterates over ids (one id at a time), finds matching strings in g, and writes them to your environment as a vector. Because we are using assign(), we expect a new vector to appear in our environment after each iteration of the loop.

# For-loop with assign
for(i in ids){
a <- paste0("Sample ", i, "_")
h <- g[grep(a, g)]
h_name <- paste0("sample_", i, "_group")
assign(x = h_name, value = h)
}

That technically works, but it's not the best. You may find that it is actually more convenient to use lists (a vector of vectors) to store information from a for-loop. It's fast to program, you don't have a bunch of new objects crowding your workspace, and all the scary things (not really) in that link above won't be a problem. Here's how you could do that:

# Save the results of a for-loop in a list!
# First, make a blank list to hold the results
results <- list()
for(i in ids){
a <- paste0("Sample ", i, "_")
h <- g[grep(a, g)]
h_name <- paste0("sample_", i, "_group")
results[[h_name]] <- h
}
results
#> $sample_12_group
#> [1] "New AS Plate 21_AS Plate_Sample 12_50.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 12_100.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 12_25.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 12_250.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 12_500.fcs"
#>
#> $sample_1_group
#> [1] "New AS Plate 21_AS Plate_Sample 1_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 1_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 1_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 1_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 1_500.fcs"
#>
#> $sample_10_group
#> [1] "New AS Plate 21_AS Plate_Sample 10_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 10_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 10_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 10_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 10_500.fcs"
#>
#> $sample_11_group
#> [1] "New AS Plate 21_AS Plate_Sample 11_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 11_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 11_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 11_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 11_500.fcs"

Extra credit

For-loops are great: it's easy to see what's going on inside of them, its easy to do a lot of data handling in them, and they are usually reasonably fast to execute. But sometimes its all about speed. R is vectorized ([I'm honestly not exactly sure what this means][2] besides "it can do multiple calculations simultaneously"), but a for-loop doesn't take advantage of this very well. The apply() family of vectorized functions do, and they can usually be easy to implement in cases where you might also use a for-loop. Here's how you could do that with your data:

# Vectorized
lapply(ids, function(i) g[grep(paste0("Sample ", i, "_"), g)])
#> [[1]]
#> [1] "New AS Plate 21_AS Plate_Sample 12_50.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 12_100.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 12_25.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 12_250.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 12_500.fcs"
#>
#> [[2]]
#> [1] "New AS Plate 21_AS Plate_Sample 1_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 1_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 1_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 1_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 1_500.fcs"
#>
#> [[3]]
#> [1] "New AS Plate 21_AS Plate_Sample 10_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 10_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 10_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 10_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 10_500.fcs"
#>
#> [[4]]
#> [1] "New AS Plate 21_AS Plate_Sample 11_100.fcs"
#> [2] "New AS Plate 21_AS Plate_Sample 11_25.fcs"
#> [3] "New AS Plate 21_AS Plate_Sample 11_250.fcs"
#> [4] "New AS Plate 21_AS Plate_Sample 11_50.fcs"
#> [5] "New AS Plate 21_AS Plate_Sample 11_500.fcs"
Created on 2021-10-14 by the reprex package (v2.0.1)

Data:

g <- c("New AS Plate 21_AS Plate_Sample 12_50.fcs", 
"New AS Plate 21_AS Plate_Sample 1_100.fcs",
"New AS Plate 21_AS Plate_Sample 1_25.fcs",
"New AS Plate 21_AS Plate_Sample 1_250.fcs",
"New AS Plate 21_AS Plate_Sample 1_50.fcs",
"New AS Plate 21_AS Plate_Sample 1_500.fcs",
"New AS Plate 21_AS Plate_Sample 10_100.fcs",
"New AS Plate 21_AS Plate_Sample 10_25.fcs",
"New AS Plate 21_AS Plate_Sample 10_250.fcs",
"New AS Plate 21_AS Plate_Sample 10_50.fcs",
"New AS Plate 21_AS Plate_Sample 10_500.fcs",
"New AS Plate 21_AS Plate_Sample 11_100.fcs",
"New AS Plate 21_AS Plate_Sample 11_25.fcs",
"New AS Plate 21_AS Plate_Sample 11_250.fcs",
"New AS Plate 21_AS Plate_Sample 11_50.fcs",
"New AS Plate 21_AS Plate_Sample 11_500.fcs",
"New AS Plate 21_AS Plate_Sample 12_100.fcs",
"New AS Plate 21_AS Plate_Sample 12_25.fcs",
"New AS Plate 21_AS Plate_Sample 12_250.fcs",
"New AS Plate 21_AS Plate_Sample 12_500.fcs")

[1]: Why is using assign bad?)
[2]: How do I know a function or an operation in R is vectorized?

Appending a list in a loop (R)

There are four errors in your approach.

First, file.names <- dir(path, pattern =".csv") will extract just file names, without path. So, when you try to import then, read.csv() doesn't find.

Building the path

You can build the right path including paste0():

path = "~/path/to/csv/"
file.names <- paste0(path, dir(path, pattern =".csv"))

Or file.path(), which add slashes automaticaly.

path = "~/path/to/csv"
file.names <- file.path(path, dir(path, pattern =".csv"))

And another way to create the path, for me more efficient, is that suggested in the answer commented by Tung.

file.names <- list.files(path = "~/path/to/csv", recursive = TRUE,
pattern = "\\.csv$", full.names = TRUE)

This is better because in addition to being all in one step, you can use within a directory containing multiple files of various formats. The code above will match all .csv files in the folder.

Importing, selecting and creating the list

The second error is in mylist <- c(). You want a list, but this creates a vector. So, the correct is:

mylist <- list()

And the last error is inside the loop. Instead of create other list when appending, use the same object created before the loop:

for(i in 1:length(file.names)){
datatmp <- read.csv(file.names[i], sep=";", stringsAsFactors=FALSE)
listtmp = datatmp[, 6]
mylist <- append(mylist, list(listtmp))
}
mylist

Another approach, easier and cleaner, is looping with lapply(). Just this:

mylist <- lapply(file.names, function(x) {
df <- read.csv(x, sep = ";", stringsAsFactors = FALSE)
df[, 6]
})

Hope it helps!

loop to assign new objects names based on list in r

You may need to use get() first to access the object in your environment, create the name of the new object, then use assign() to assign.

rm(list = ls())

# put some things in the environment
x <- list(a = "hello", b = "world")
y <- list(a = "hola", b = "mundo")
z <- list(a = "bonjour", b = "monde")

# loop through environment objects;
# use get() to access, and assign() to put back
for (i in ls()) {
temp <- get(i)
new_name <- temp$a
assign(new_name, temp)
rm(i, temp) # removes object i, not the object whose name is stored in i
}

ls()

Note that with this code, you'll have two objects with different names but same content.



Related Topics



Leave a reply



Submit