lapply functions inside each other does not work as expected - r

I have two lists and I must use for and if condition for my functions over these lists. I then decide to use lapply function. I used lapply function but my code becomes so difficult and do not work. How can I make my code work in an easy way. Is there a good way to do not use many lapply functions.
The idea of my code:
First have some lists.
These lists does not need to be all the same lengths or even all > 0.
So, my code check each list. if it is > 0 or not.
If it is > 0 then:
check the values of the second list.
If the values equal specific values then this values will changes to new values.
The last steps must applied to all the lists that I have.
Here is my code:
the function gave me NULL
nx <- list(1, 1) ## if my list > 0 then check it
x.t <- list(c(2, 3, 4, 4), c(2, 4, 5, 6)) #the list to apply if statement on it.
lapply(nx, function(x) if (x > 0) {
do.t <- lapply(x.t, function(x) { which(x %in% c(2, 7:10))})
##check the values of my list.
lapply(nx, function(x){
lapply(1:length(x), function(i){ for (j in 1:x[[i]]){ ## here I would like j from 1 to length of x where x is a list of two elements.
if (x.t[[i]][do.t[[j]]] == 2) ## here I want to have a condition says that, if the element of each list is equal 2 then this element will have the value 2.5.
x.t[[i]] <- 2.5
}})})})
my function will includes many lists where the condition will be extend. For example,
if (x.t[[i]][do.t[[j]]] == 2){
x.t[[i]] <- 2.5
}else{ some condition}elese{other condtion}
and so on.
the result.
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
NULL
[[1]][[2]]
[[1]][[2]][[1]]
NULL
[[2]]
[[2]][[1]]
[[2]][[1]][[1]]
NULL
[[2]][[2]]
[[2]][[2]][[1]]
NULL
My function is so complicated and hence I provide this example very similar to my original function.

As a general function maybe it's better to divide the code into parts, each one doing just one thing.
Note that the lapply passes entire vectors, the elements of the list x.t to the function. Then, complicated loops through the elements of a vector, processing one at a time.
complicated <- function(x){
for(i in seq_along(x)){
if(x[i] > 0){
if(x[i] == 2)
x[i] <- 2.5
}
}
x
}
x.t.2 <- lapply(x.t, function(x){
x <- complicated(x)
x
})
x.t.2
#[[1]]
#[1] 2.5 3.0 4.0 4.0
#
#[[2]]
#[1] 2.5 4.0 5.0 6.0

Related

Avoid storing null values when skipping an iteration in a for loop

Exist a way to avoiding to store null values in an iterative process when some condition is activated to skip to the next iteration? The intention of "how to solve" this problem is with the structure itself of the loop
[CONTEXT]:
I refer to the case when you need to use a storing mechanism inside a loop in conjunction with a conditional statement, and it is given the scenario where basically one of the possibles path is not of your interest. In the honor to give the treatment in the moment, and not posterior of the computation, you skip to the next iteration.
[EXAMPLE]
Suppose given a certain sequence of numbers, I interested only in stored the numbers of the sequence that are greater than 2 in a list.
storeGreaterThan2 <- function(x){
y <- list()
for (i in seq_along(x)) {
if (x[i] > 2) {
y[[i]] <- x[i]
} else {
next
}
}
y
}
The previous function deal with the final purpose, but when the condition to skip the iteration is activated the missing operation in the index is filled with a null value in the final list.
> storeGeaterThan2(1:5)
[[1]]
NULL
[[2]]
NULL
[[3]]
[1] 3
[[4]]
[1] 4
[[5]]
[1] 5
In the spirit of dealing with the problem inside the structure of the loop, how it could deal with that?
This is a rather strange example, and I wonder if it's an x-y problem. It may be better to say more about your situation and what you ultimately want to do. For example, there are different ways of trying to do this depending on if the function's input will always be an ascending sequence. #Dave2e's comment that there will be better ways depending of what you are really after is right on the mark, in my opinion. At any rate, you can simply removed the NULL elements before you return the list. Consider:
storeGreaterThan2 <- function(x){
y <- list()
for(i in seq_along(x)) {
if(x[i] > 2) {
y[[i]] <- x[i]
} else {
next
}
}
y <- y[-which(sapply(y, is.null))]
return(y)
}
storeGreaterThan2(1:5)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4
#
# [[3]]
# [1] 5
Here is a possible way to do this without ever having stored the NULL element, rather than cleaning it up at the end:
storeGreaterThan2 <- function(x){
y <- list()
l <- 1 # l is an index for the list
for(i in seq_along(x)){ # i is an index for the x vector
if(x[i] > 2) {
y[[l]] <- x[i]
l <- l+1
}
}
return(y)
}

indexing through values of a nested list using mapply

I have a list of lists, with each sub-list containing 3 values. My goal is to cycle through every value of this nested list in a systematic way (i.e. start with list 1, go through all 3 values, go to list 2, and so on), applying a function to each. But my function hits missing values and breaks and I've traced the problem to the indexing itself, which doesn't behave in the way I am expecting. The lists are constructed as:
pop <- 1:100
treat.temp <- NULL
treat <- NULL
## Generate 5 samples of pop
for (i in 1:5){
treat.temp <- sample(pop, 3)
treat[[i]] <- treat.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
Illustrative function and results.
test.function <- function(j, k){
for (n in 1:3){
print(k[[n]][j])
}
}
results <- mapply(test.function, iterations, treat)
[1] 61
[1] 63
[1] 73
[1] NA
[1] NA
[1] NA
[1] NA
[1] NA
<snipped>
For the first cycle through 'j', this works. But after that it throws NAs. But if I do it manually, it returns the values I would expect.
> print(treat[[1]][1])
[1] 61
> print(treat[[1]][2])
[1] 63
> print(treat[[1]][3])
[1] 73
> print(treat[[2]][1])
[1] 59
> print(treat[[2]][2])
[1] 6
> print(treat[[2]][3])
[1] 75
<snipped>
I'm sure this is a basic question, but I can't seem to find the right search terms to find an answer here or on Google. Thanks in advance!
Edited to Add: MrFlick's answer works well for my problem. I have multiple list inputs (hence mapply) in my actual use. A more detailed example, with a few notes.
pop <- 1:100
years <- seq.int(2000, 2014, 1)
treat.temp <- NULL
treat <- NULL
year.temp <- NULL
year <- NULL
## Generate 5 samples of treated states, control states and treatment years
for (i in 1:5){
treat.temp <- sample(pop, 20)
treat[[i]] <- treat.temp
year.temp <- sample(years, 1)
year[[i]] <- year.temp
}
## Create a list with which to index mapply
iterations <- (1:5)
## Define function
test.function <- function(j, k, l){
for (n in 1:3){
## Cycles treat through each value of jXn
print(k[n])
## Holds treat (k) fixed for each 3 cycle set of n (using first value in each treat sub-list); cycles through sub-lists as j changes
print(k[1])
## Same as above, but with 2nd value in each sub-list of treat
print(k[2])
## Holds year (l) fixed for each 3 cycle set of n, cycling through values of year each time j changes
print(l[1])
## Functionally equivalent to
print(l)
}
}
results <- mapply(test.function, iterations, treat, year)
Well, you might be misunderstanding how mapply works. The function will loop through both of the iterations you pass as parameters, which means treat will also be subset each iteration. Essentially, the functions being called are
test.function(iterations[1], treat[[1]])
test.function(iterations[2], treat[[2]])
test.function(iterations[3], treat[[3]])
...
and you seem to treat the k variable as if it were the entire list. Also, you have your indexes backwards as well. But just to get your test working, you can do
test.function <- function(j, k){
for (n in 1:3) print(k[n])
}
results <- mapply(test.function, iterations, treat)
but this isn't really a super awesome way to iterate a list. What exactly are you trying to accomplish?

R split numeric vector at position

I am wondering about the simple task of splitting a vector into two at a certain index:
splitAt <- function(x, pos){
list(x[1:pos-1], x[pos:length(x)])
}
a <- c(1, 2, 2, 3)
> splitAt(a, 4)
[[1]]
[1] 1 2 2
[[2]]
[1] 3
My question: There must be some existing function for this, but I can't find it? Is maybe split a possibility? My naive implementation also does not work if pos=0 or pos>length(a).
An improvement would be:
splitAt <- function(x, pos) unname(split(x, cumsum(seq_along(x) %in% pos)))
which can now take a vector of positions:
splitAt(a, c(2, 4))
# [[1]]
# [1] 1
#
# [[2]]
# [1] 2 2
#
# [[3]]
# [1] 3
And it does behave properly (subjective) if pos <= 0 or pos >= length(x) in the sense that it returns the whole original vector in a single list item. If you'd like it to error out instead, use stopifnot at the top of the function.
I tried to use flodel's answer, but it was too slow in my case with a very large x (and the function has to be called repeatedly). So I created the following function that is much faster, but also very ugly and doesn't behave properly. In particular, it doesn't check anything and will return buggy results at least for pos >= length(x) or pos <= 0 (you can add those checks yourself if you're unsure about your inputs and not too concerned about speed), and perhaps some other cases as well, so be careful.
splitAt2 <- function(x, pos) {
out <- list()
pos2 <- c(1, pos, length(x)+1)
for (i in seq_along(pos2[-1])) {
out[[i]] <- x[pos2[i]:(pos2[i+1]-1)]
}
return(out)
}
However, splitAt2 runs about 20 times faster with an x of length 106:
library(microbenchmark)
W <- rnorm(1e6)
splits <- cumsum(rep(1e5, 9))
tm <- microbenchmark(
splitAt(W, splits),
splitAt2(W, splits),
times=10)
tm
Another alternative that might be faster and/or more readable/elegant than flodel's solution:
splitAt <- function(x, pos) {
unname(split(x, findInterval(x, pos)))
}

append results of loop into numeric vector

I would like to create a numeric vector with the results of a loop such as
> for (i in 1:5) print(i+1)
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
It seems strange that the same expression without 'print' returns nothing
> for (i in 1:5) i+1
>
Does anyone have an explanation/solution?
This is standard behaiviour -- when you say you want to create a numeric vector,
print will not do that
The expression in a for loop is an argument to the primitive function for
From ?`for` in the value section
for, while and repeat return NULL invisibly. for sets var to the last
used element of seq, or to NULL if it was of length zero.
print prints the results to the console.
for(i in 1:5) i + 1
merely calculates i + 1 for each iteration and returns nothing
If you want to assign something then assign it using <-, or less advisably assign
You can avoid an explicit loops by using sapply. This (should) avoid any pitfalls of growing vectors
results <- sapply(1:5, function(i) { i + 1})
Now frankly, there must be a better solution than this
loopee <- function(x){
res <- vector(mode = "numeric", length(x))
for (i in 1:x) {res[i] <- i+1}
return(res)}
> loopee(5)
[1] 2 3 4 5 6

product of elements of the vector

I want to write a function that, given a vector v computes the product of all the entries in v. (There is a function in R that does this, but I want to write one myself.)
I tried however how can I get for product of any elements in a vector?
product <- function(v){
out <- 1
for(i in 1:length(v)){
out <- out*v[i]
}
out
}
If you use ... as the argument to your function, you can pass it several objects or just one. Inside the function, you can convert to a list and use Reduce to apply a function (*) recursively to the list. If you combine list, unlist and as.list you can make this very general. The following will work with a vector, or with 2 or more numbers, or a mixture of vectors and single numbers.
> product <- function(...) Reduce("*", as.list(unlist(list(...))))
> product(2, 7, 3)
[1] 42
> product(c(2, 7, 3))
[1] 42
> product(2, c(7, 3))
[1] 42
The use of Recall for tail recursion:
prd2 <- function(x)
if(length(x) == 2) { x[1] *x[-1] } else x[1] * Recall(x[-1])
prd2(c(2,3,4))
#[1] 24

Resources