I have a nested loop that I need to iterate over. I want to go to the end of the list (in this case second item of the parent list), and add item to it if it isn't nested loop anymore. So loop may have many levels of nested loop. Right now, I'm only getting second list as a return. How do I track parent list?
a <- list( x = list(1,2,3),y =list(4,5,6))
con=TRUE
while(con){
i <-length(a)
for(k in i:i){
if(!typeof(a[[k]])=="list"){
a[[k+1]] <- "test"
con=FALSE
}else{
a <- a[[k]]
i <- length(a)
}
}
}
Expected Result:a <- list(x = list(1,2,3), y =list(4,5,6, "test"))
Result: a <- list(4,5,6,"test")
library(magrittr)
a <- list( x = list(1,2,3),y =list(4,5,6), z = 1)
temp <- lapply(a, typeof) %>% unlist
tempList <- (temp!="list")
if (sum(tempList) > 0) {
a[[max(which(tempList == FALSE))]] %<>% append("test")
} else {
a[[length(a)]] %<>% append("test")
}
It isn't clear to me what it is that you want to do, but
just concentrating on your example, this would work.
In short, see which elements of the parent list are not Lists, and for the last one of them add "test". If all of them are lists, then add "test" to the last one.
Related
I would like to iteratively add elements to a list over which I loop:
list = as.list(c(1,2,3))
list
for (x in list) {
new_element = as.list(x^2)
print(new_element)
list = union(list, new_element)
}
list
However, R takes only the original 3 elements in the loop.
I would like that the loop continues with the new elements. Any ideas on how I could adjust my code? Thanks!
Use a while loop rather than a for loop, together with break to eventually terminate:
mylist = as.list(c(1,2,3))
i <- 1
while(TRUE){
x <- mylist[[i]]
if(x<10){
new_element <- as.list(x^2)
print(new_element)
mylist = union(mylist, new_element)
i <- i+1
} else {
break
}
}
This causes mylist to have 7 items (lists containing 1,2,3,4,9,16,81 respectively) when the loop terminates.
I have a list of the following type
categories = list(
c("Women","Clothing", "Jeans"),
c("Women","Clothing", "Sweaters"),
c("Men","Accessories", "Belts"),
c("Women", "Accessories", "Jewelry" ))
I want to parse this list and create a list of lists to export in JSON and it should have the following structure:
Women={
Clothing= {
Jeans{},
Sweaters{}
},
accesories={
Jewleery{}
}
},
Men ={
Accessires={
Belts={}
}
So it should go over each element which is a char vector contained in the list and check if there is such element in the final list, if there isn't it should append it. It should append the element at the proper level. For example if Clothing is second element to Woman, it should append to the Women list of the final list. Or if Sweaters is thrid element to Women.Clothing it should apppend Clothing list of the Women list of the final list.
If the element exists at the given level already it should not append, instead it should go to next element in the char vector.
In the char vectors of the input lsit, the first element is always level 1 the second level 2 the third level 3 etc..
It should be done recursively, I tried few times but I have no idea how to assign to a nested list, specifically i need to do nested assigns.
I made the data into a matrix, transposed, then a dataframe:
x <- data.frame(t(vapply(categories, identity, character(3))), stringsAsFactors = F)
Then split, and lapply. You could do this recursively if you have more than 3 levels:
lapply(split(x, x$X1), function(df) {
lapply(split(df, df$X2), function(df) {
lapply(split(df, df$X3), function(x) list())
})
})
If you are looking for a recursive solution, then the following may help you:
output the full directory trajectory within a string at the end
## construct a data frame from list
df <- data.frame(matrix(unlist(categories),nrow = length(categories),byrow = T),stringsAsFactors = F)
## recursion function that makes nested list
f <- function(df, k=1) {
if (k == ncol(df)) return(lapply(split(df,df[,k]), toString)) ##
return(lapply(split(df,df[,k]), function(df) f(df, k+1)))
}
The nested list output looks as below
> f(df)
$Men
$Men$Accessories
$Men$Accessories$Belts
[1] "Men, Accessories, Belts"
$Women
$Women$Accessories
$Women$Accessories$Jewelry
[1] "Women, Accessories, Jewelry"
$Women$Clothing
$Women$Clothing$Jeans
[1] "Women, Clothing, Jeans"
$Women$Clothing$Sweaters
[1] "Women, Clothing, Sweaters"
output empty lists at the end
f <- function(df, k=1) {
if (k == ncol(df)) return(lapply(split(df,df[,k]), function(v) list()))
return(lapply(split(df,df[,k]), function(df) f(df, k+1)))
}
which gives:
> f(df)
$Men
$Men$Accessories
$Men$Accessories$Belts
list()
$Women
$Women$Accessories
$Women$Accessories$Jewelry
list()
$Women$Clothing
$Women$Clothing$Jeans
list()
$Women$Clothing$Sweaters
list()
I'm new to R. Reading Book Of R by Tilman Davies. An example is provided for how to use an externally defined helper function which incidentally utilizes double square brackets [[]]. Please explain what helper.call[[1]] and helper.call[[2]] are doing and use of double brackets here.
multiples_helper_ext <- function(x=foo,matrix.flags,mat=diag(2){
indexes <- which(matrix.flags)
counter <- 0
result <- list()
for(i in indexes){
temp <- x[[i]]
if(ncol(temp)==nrow(mat)){
counter <- counter+1
result[[counter]] <- temp%*%mat
}
}
return(list(result,counter))
}
multiples4 <- function(x,mat=diag(2),str1="no valid matrices",str2=str1){
matrix.flags <- sapply(x,FUN=is.matrix)
if(!any(matrix.flags)){
return(str1)
}
helper.call <- multiples_helper_ext(x,matrix.flags,mat=diag(2)
result <- helper.call[[1]] #I dont understand this use of double bracket
counter <- helper.call[[2]] #and here either
if(counter==0){
return(str2)
} else {
return(result)
}
}
foo <- list(matrix(1:4,2,2),"not a matrix","definitely not a matrix",matrix(1:8,2,4),matrix(1:8,4,2))
In R there are two basic types of objects: lists and vectors. The items of lists can be other objects, the items of of vectors are usually numbers, strings, etc.
To access items in a list, you use the double bracket [[]]. This gives back the object at that place of the list.
So
x <- 1:10
x is now a vector of integers
L <- list( x, x, "hello" )
L is a list whose first item is the vector x, its second item is the vector x, and its third item is the string "hello".
L[[2]]
This give back a vector, 1:10, which is stored in the 2nd place in L.
L[2]
This is a bit confusing, but this gives back a list whose only item is 1:10, i.e. it only contains L[[2]].
In R, when you want to return multiple values, you usually do this with a list. So, you might end you function with
f <- function() {
return( list( result1="hello", result2=1:10) )
}
x = f()
Now you can access the two results with
print( x[["result1"]] )
print( x[["result2"]] )
You can also access items of a list with ''$, so instead you can write
print( x$result1 )
print( x$result2 )
The syntax [[]] is used for list in python. Your helper.call is a list (of result and counter), so helper.cal[[1]] returns the first element of this list (result).
Have a look here: Understanding list indexing and bracket conventions in R
So I am wondering how to extract randomly a string from a list in R with NO REPLACEMENT till the list is empty.
To write
sample(x, size=1, replace=FALSE)
is not helping me, since string are extracted more than once before the list gets empty.
Kind regards
In every iteration one list element will be picked, and from this element a value removed. If there is only one value left, the list element is removed.
x <- list(a = "bla", b = c("ble", "bla"), c = "bli")
while (length(x) > 0) {
s <- sample(x, size = 1)
column <- x[[names(s)]]
value <- sample(unlist(s, use.names = FALSE), size = 1)
list_element_without_value <- subset(column, column != value)
x[[names(s)]] <- if (length(list_element_without_value) == 0) {
NULL
} else {
list_element_without_value
}
}
sample(x)
You can't use size=1 on repeated calls and expect it to know not to grab values previously selected. You have to grab all the values you want at one time. This code will shuffle your data and then you can grab the first element when you need it. Then the next time you need something grab the second... And so on.
I have a nested list like so:
smth <- list()
smth$a <- list(a1=1, a2=2, a3=3)
smth$b <- list(b1=4, b2=5, b3=6)
smth$c <- "C"
The names of every element in the list are unique.
I would like to get an element from such a list merely by name without knowing where it is located.
Example:
getByName(smth, "c") = "C"
getByName(smth, "b2") = 5
Also I don't really want to use unlist since the real list has a lot of heavy elements in it.
The best solution so far is the following:
rmatch <- function(x, name) {
pos <- match(name, names(x))
if (!is.na(pos)) return(x[[pos]])
for (el in x) {
if (class(el) == "list") {
out <- Recall(el, name)
if (!is.null(out)) return(out)
}
}
}
rmatch(smth, "a1")
[1] 1
rmatch(smth, "b3")
[1] 6
Full credit goes to #akrun for finding it and mbedward for posting it here