Reputation: 7313
I am trying to replicate 81-place cryoboxes used in lab storage system using a nested for loop. The following code illustrates the problem using 3-place boxes:
urine_random_df <- as.data.frame(c(seq(from = 10, to = 12, by = 1)))
boxcells <- vector()
cell_placeholder <- as.data.frame(c(seq(from = 1, to = 3, by = 1)))
for (i in 1: 3){
#boxcells <- paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,])))
for (j in 1: nrow(cell_placeholder)){
boxcells <- c(boxcells, paste(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))), cell_placeholder[j,], sep = "-"))
}
}
boxcells <- data.frame(boxcells)
names(boxcells) <- "box cells"
boxcells
The result of above is:
box cells
1 NEW0010-1
2 NEW0010-2
3 NEW0010-3
4 NEW0011-1
5 NEW0011-2
6 NEW0011-3
7 NEW0012-1
8 NEW0012-2
9 NEW0012-3
However, I would like to group the cells under their respective boxes like so:
box cells
1 NEW0010
2 NEW0010-1
3 NEW0010-2
3 NEW0010-3
4 NEW0011
5 NEW0011-1
6 NEW0011-2
7 NEW0011-3
8 NEW0012
9 NEW0012-1
10 NEW0012-2
11 NEW0012-3
I tried to achieve this by adding boxcells <- paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,])))
in the outer loop. When I re-ran the code with this piece, I get only the last box like so:
box cells
1 NEW0012
2 NEW0012-1
3 NEW0012-2
4 NEW0012-3
It appears each iteration of the loop erases the last such that upon completion of the entire loop, only the last box remains. I found an existing thread here which suggests moving the "initialisation statements" outside the loop. However, in this case, the initialisation statements urine_random_df...
, boxcells...
and cell_placeholder...
are already outside the loop. Thoughts?
Upvotes: 1
Views: 2047
Reputation: 121568
If you want to group result better to choose another structure to store your result. Here 2 ways to simply resolve your problem:
nn <- paste0('NEW',sprintf("%04d",10:12))
setNames(lapply(nn,function(x){
paste(x,1:3,sep='-')
}),nn)
$NEW0010
[1] "NEW0010-1" "NEW0010-2" "NEW0010-3"
$NEW0011
[1] "NEW0011-1" "NEW0011-2" "NEW0011-3"
$NEW0012
[1] "NEW0012-1" "NEW0012-2" "NEW0012-3"
transform(expand.grid(nn,1:3),Var2=paste(Var1,Var2,sep='-'))
Var1 Var2
1 NEW0010 NEW0010-1
2 NEW0011 NEW0011-1
3 NEW0012 NEW0012-1
4 NEW0010 NEW0010-2
5 NEW0011 NEW0011-2
6 NEW0012 NEW0012-2
7 NEW0010 NEW0010-3
8 NEW0011 NEW0011-3
9 NEW0012 NEW0012-3
Upvotes: 0
Reputation: 42283
I think the complication here comes from collecting the output of the loop as a vector rather than a list.
Here it is using a list, then unlisting and converting to a dataframe. The output is exactly as requested
urine_random_df <- as.data.frame(c(seq(from = 10, to = 12, by = 1)))
boxcells <- list()
cell_placeholder <- as.data.frame(c(seq(from = 1, to = 3, by = 1)))
n <- nrow(cell_placeholder)
for (i in 1:n){
tmp <- vector()
tmp <- c(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))))
for (j in 1:n){
tmp <- c(tmp, paste(paste0("NEW", sprintf("%04d", as.numeric(urine_random_df[i,]))), cell_placeholder[j,], sep = "-"))
}
boxcells[[i]] <- tmp
}
boxcells <- data.frame(unlist(boxcells))
names(boxcells) <- "box cells"
boxcells
Which gives:
box cells
1 NEW0010
2 NEW0010-1
3 NEW0010-2
4 NEW0010-3
5 NEW0011
6 NEW0011-1
7 NEW0011-2
8 NEW0011-3
9 NEW0012
10 NEW0012-1
11 NEW0012-2
12 NEW0012-3
Upvotes: 1
Reputation: 92282
I can think of very rare situations when you would do a nested for
loop in R, even single for
loop is very rare.
I would solve this by doing something like
temp <- expand.grid(sprintf("%04d", as.numeric(urine_random_df[,1])), c("", paste0("-",cell_placeholder[, 1])))
boxcells <- data.frame(box_cells = paste0("NEW", paste0(temp[, 1], temp[, 2])))
Which will return
box_cells
1 NEW0010
2 NEW0011
3 NEW0012
4 NEW0010-1
5 NEW0011-1
6 NEW0012-1
7 NEW0010-2
8 NEW0011-2
9 NEW0012-2
10 NEW0010-3
11 NEW0011-3
12 NEW0012-3
If you don't like the order, you could reorder by
boxcells <- data.frame(box_cells = boxcells[order(as.numeric(substr(boxcells$box_cells, 6,7))), ])
box_cells
1 NEW0010
2 NEW0010-1
3 NEW0010-2
4 NEW0010-3
5 NEW0011
6 NEW0011-1
7 NEW0011-2
8 NEW0011-3
9 NEW0012
10 NEW0012-1
11 NEW0012-2
12 NEW0012-3
Upvotes: 0