Home > Blockchain >  Using assign to create objects in a for loop
Using assign to create objects in a for loop

Time:11-05

I have example data as follows:

# Two lists of vectors

A <- list()
B <- list()

patterns <- c("A","B")

A[[1]] <- c("Aa", "Aa", "Ab", NA)
names(A)[1] <- "A1"

A[[2]] <- c("Aa", "Aa", "Ab", NA, NA)
names(A)[2] <- "A2"

B[[1]] <- c("Aa", "Ab", NA, NA, "Ab")
names(B)[1] <- "B1"

B[[2]] <- c("Aa", "Ab", NA, "Ab")
names(B)[2] <- "B2"

What I would like to do is to create data.frames from each list item, with only the unique values per list item.

for (j in 1:length(patterns)) {  

    # Keep unique values
    assign(paste0("Pattern_", patterns[[j]]), lapply(paste0("Pattern_", patterns[[j]]) ,function(x) unique(na.omit(x))))

    # Make lengths equal
    assign(paste0("Pattern_", patterns[[j]]), lapply(paste0("Pattern_", patterns[[j]]), `length<-`, max(lengths(paste0("Pattern_", patterns[[j]])))))

    # Create data.frame
    assign(paste0("Pattern_", patterns[[j]]), data.frame(matrix(unlist(paste0("Pattern_", patterns[[j]])), nrow=length(paste0("Pattern_", patterns[[j]])), byrow=TRUE),stringsAsFactors=FALSE))
}

I thought I did it right but somehow I get is:

enter image description here

What I want is:

A <- lapply(A ,function(x) unique(na.omit(x)))
A <- lapply(A, `length<-`, max(lengths(A)))
# https://stackoverflow.com/questions/12639501/convert-list-to-data-frame-while-keeping-list-element-names
A <- data.frame(ID = rep(names(A), sapply(A, length)),
                 Match = unlist(A), row.names = NULL)

  ID Match
1 A1    Aa
2 A1    Ab
3 A2    Aa
4 A2    Ab

What am I doing wrong?

CodePudding user response:

I would just do a simpler approach:

library(tidyverse)
# Two lists of vectors

A <- list()
B <- list()

patterns <- c("A","B")

A[[1]] <- c("Aa", "Aa", "Ab", NA)
names(A)[1] <- "A1"

A[[2]] <- c("Aa", "Aa", "Ab", NA, NA)
names(A)[2] <- "A2"

B[[1]] <- c("Aa", "Ab", NA, NA, "Ab")
names(B)[1] <- "B1"

B[[2]] <- c("Aa", "Ab", NA, "Ab")
names(B)[2] <- "B2"


stack(A) %>% distinct(ind, values)
#>   values ind
#> 1     Aa  A1
#> 2     Ab  A1
#> 3   <NA>  A1
#> 4     Aa  A2
#> 5     Ab  A2
#> 6   <NA>  A2

You can then just filter out the NAs.

Created on 2021-11-05 by the reprex package (v2.0.0)

EDIT

I would suggest to never use assign because you are introducing side-effects into your code.

The problem with the code is that you never call a list, you rather use a string in your lapply() function:

lapply(paste0("Pattern_", patterns[[j]]) ,function(x) unique(na.omit(x)))

I kept the assign, even though I don't like it.

for (j in patterns) {  
  new_list <- lapply(get(j) ,function(x) unique(na.omit(x)))
  assign(paste0("Pattern_", j), stack(new_list))
}
  • Related