Summary a list of integers into two columns in R - r

This is what I've got (a list):
>head(indexes)
[[1]]
numeric(0)
[[2]]
[1] 12
[[3]]
[1] 13
[[4]]
[1] 2 3
[[5]]
[1] 25
[[6]]
[1] 26
> all(vapply(indexes, is.numeric, TRUE)) # (note that..)
[1] TRUE
.. and this is what I want (same information for me):
>head(res,6)
[,1] [,2]
[1,] 2 12
[2,] 3 13
[3,] 4 2
[4,] 4 3
[5,] 5 25
[6,] 6 36
Is there a clever way to do this?
I tried a trick with naming the list:
names(indexes) <- 1:lenght(indexes)
res <- c(indexes, recursive=TRUE)
res <- cbind(as.integer(names(res)), res)
But R (such a kind damn kid!) breaks everything down by renaming the identical rows in an ambiguous fashion:
>head(res)
res
2 2 2
3 3 3
41 41 2
42 42 3
5 5 5
6 6 6
# ... (think about what happens around lines 3675.. 41158..)
.. if this was the clever way, how do I prevent the renaming?

Wops! Okay, nailed it:
res <- cbind(
rep(1:length(indexes), vapply(indexes,length,1)),
c(indexes,recursive=TRUE)
)
.. just tell me if anyone found a better way, then :)

Related

How to use "for loop" to get couples of indexes every time in R?

Let's assume I have this vector v:
v = seq(1,30,1)
I write this simple loop:
for(i in v) {
print(i)
}
However, I would like to write a loop that gives me, in time, 1:2, 3:4, 5:6, 7:8, etc. I would then get:
[1] 1,2
[1] 3,4
[1] 5,6
[1] 7,8
...
Can anyone help me?
Thanks!
Maybe you can generate v with step of 2.
v = seq(1,30,2)
for(i in v) {
cat(paste(i, i + 1, sep = ','), '\n')
}
#1,2
#3,4
#5,6
#7,8
#9,10
#11,12
#13,14
#...
If you want to keep your approach, try this:
for(i in v[-length(v)]) {
print(c(i, i+1))
}
[1] 1 2
[1] 2 3
[1] 3 4
...
Adding i to a subset.
for(i in v) {
print(v[0:1 + i])
}
# [1] 1 2
# [1] 2 3
# [1] 3 4
# [1] ...
Alternatively you could also consider this:
cbind(v[-length(v)], v[-1])
# [,1] [,2]
# [1,] 1 2
# [2,] 2 3
# [3,] 3 4
# [4,] 4 5
# [5,] 5 6
# [6,] ...
You need to update the print command and use the method range
https://www.w3schools.com/python/ref_func_range.asp
for i in range(0,len(v)-1,2):
print(str(v[i])+","+str(v[i+1]))
In this way you should get
1,2
3,4
5,6
7,8
...
Try this
> for(i in v) if (i%%2) print(c(i,i+1))
[1] 1 2
[1] 3 4
[1] 5 6
[1] 7 8
[1] 9 10
[1] 11 12
[1] 13 14
[1] 15 16
[1] 17 18
[1] 19 20
[1] 21 22
[1] 23 24
[1] 25 26
[1] 27 28
[1] 29 30

Getting all the combination of numbers from a list that would sum to a specific number

I have the following list of numbers (1,3,4,5,7,9,10,12,15) and I want to find out all the possible combinations of 3 numbers from this list that would sum to 20.
My research on stackoverflow has led me to this post:
Finding all possible combinations of numbers to reach a given sum
There is a solution provided by Mark which stand as follows:
subset_sum = function(numbers,target,partial=0){
if(any(is.na(partial))) return()
s = sum(partial)
if(s == target) print(sprintf("sum(%s)=%s",paste(partial[-1],collapse="+"),target))
if(s > target) return()
for( i in seq_along(numbers)){
n = numbers[i]
remaining = numbers[(i+1):length(numbers)]
subset_sum(remaining,target,c(partial,n))
}
}
However I am having a hard time trying to tweak this set of codes to match my problem. Or may be there is a simpler solution?
I want the output in R to show me the list of numbers.
Any help would be appreciated.
You can use combn function and filter to meet your criteria. I have performed below calculation in 2 steps but one can perform it in single step too.
v <- c(1,3,4,5,7,9,10,12,15)
AllComb <- combn(v, 3) #generates all combination taking 3 at a time.
PossibleComb <- AllComb[,colSums(AllComb) == 20] #filter those with sum == 20
#Result: 6 sets of 3 numbers (column-wise)
PossibleComb
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 1 1 1 3 3 4
# [2,] 4 7 9 5 7 7
# [3,] 15 12 10 12 10 9
#
# Result in list
split(PossibleComb, col(PossibleComb))
# $`1`
# [1] 1 4 15
#
# $`2`
# [1] 1 7 12
#
# $`3`
# [1] 1 9 10
#
# $`4`
# [1] 3 5 12
#
# $`5`
# [1] 3 7 10
#
# $`6`
# [1] 4 7 9
The combn also have a FUN parameter which we can describe to output as list and then Filter the list elements based on the condition
Filter(function(x) sum(x) == 20, combn(v, 3, FUN = list))
#[[1]]
#[1] 1 4 15
#[[2]]
#[1] 1 7 12
#[[3]]
#[1] 1 9 10
#[[4]]
#[1] 3 5 12
#[[5]]
#[1] 3 7 10
#[[6]]
#[1] 4 7 9
data
v <- c(1,3,4,5,7,9,10,12,15)

Calculate in deeper list levels R

Imagine, I have list of two levels:
lll <- list()
lll[[1]] <- list(1:10, 1:5, 1:2)
lll[[2]] <- list(10:20, 20:30)
lll
[[1]]
[[1]][[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[1]][[2]]
[1] 1 2 3 4 5
[[1]][[3]]
[1] 1 2
[[2]]
[[2]][[1]]
[1] 10 11 12 13 14 15 16 17 18 19 20
[[2]][[2]]
[1] 20 21 22 23 24 25 26 27 28 29 30
I want calculate means of these sequences. I have written a little function, which works fine:
func <- function(list.list){
lapply(1:length(list.list), function(i) mean(list.list[[i]]))
}
lapply(lll, func)
I don't like in this function, that I have to use anonymous function.
It gets even more complicated when I have list of 3 levels.
Maybe you know better ways to make calculations in which anonymous function would not be included? Should I use higher-order functions (Map, Reduce)?
I know how to write for cycle, but in this case it isn't an option.
Here's a possible solution (using rapply = recursive apply) working at any level of depth :
lll <- list()
lll[[1]] <- list(1:10, 1:5, 1:2)
lll[[2]] <- list(10:20, 20:30)
res <- rapply(lll,mean,how='replace')
> res
[[1]]
[[1]][[1]]
[1] 5.5
[[1]][[2]]
[1] 3
[[1]][[3]]
[1] 1.5
[[2]]
[[2]][[1]]
[1] 15
[[2]][[2]]
[1] 25
Setting argument how='unlist' you will get :
res <- rapply(lll,mean,how='replace')
> res
[1] 5.5 3.0 1.5 15.0 25.0

List including data.frame in R

I have known that list can include data.frame.
This is an example.
df<- cbind(column=c(1,2,3), column=c(2,3,4), column=c(3,4,5), column=c(4,5,6))
col<-list()
col[1]<- list(df[,1:2])
col[2]<- list(df[,2:3])
col[3]<- list(df[,3:4])
The result of col is that
col
[[1]]
column column
[1,] 1 2
[2,] 2 3
[3,] 3 4
[[2]]
column column
[1,] 2 3
[2,] 3 4
[3,] 4 5
[[3]]
column column
[1,] 3 4
[2,] 4 5
[3,] 5 6
However, when I use for.
col<-list()
for(i in 1:3){
col[i]<- list(df[,i:i+1])
}
The result is that
col
[[1]]
[1] 2 3 4
[[2]]
[1] 3 4 5
[[3]]
[1] 4 5 6
What is the different point of these two approaches?
How can I get same result using for.?
In the for statement you need to add parenthesis like this:
col<-list()
for(i in 1:3){
col[i]<- list(df[,i:(i+1)])
}
Basically in your code "i:i+1" is equivalent to "(i:i)+1" since ":" has priority over "+" on this operation... or in other words you are doing (i+1):(i+1)

replicate function in R returns NULL

I am confused about the output from the replicate function in R, I am trying to use it in two different ways, that (in my mind) should give a matrix as output!
so, if I use
replicate(5, seq(1,5,1))
I get a matrix 5x5
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
..and that's ok, I get that...
but, if I instead use:
replicate(5, for(i in 1:5){print(i)})
I get the following:
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
can anyone explain me why does this happen?
thanks :)
A for loop returns NULL. So in the second case, the replicate function is executing for(i in 1:5){print(i)} five times, which is why you see all those numbers printed out.
Then it is putting the return values in a list, so the return value of the replicate call is a list of five NULLs, which gets printed out. Executing
x<-replicate(5, for(i in 1:5){print(i)})
x
should clarify.
As #mrip says a for-loop returns NULL so you need to assign to an object within the loop, and return that object to replicate so it can be output. However, mrip's code still results in NULLs from each iteration of the replicate evaluation.
You also need to assign the output of replicate to a name, so it doesn't just evaporate, er, get garbage collected. That means you need to add the d as a separate statement so that the evaluation of the whole expression inside the curley-braces will return 'something' rather than NULL.
d <- numeric(5); res <- replicate(5, {
for(i in 1:5){d[i] <- print(i)} ; d}
)
[1] 1
[1] 2
snipped
[1] 4
[1] 5
> res
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
The for loop is giving a list back, while the seq() call is giving a vector back. This should give you the same as the seq() using a for loop
foo <- function(){
b = list()
for(i in 1:5) b[i] <- i
do.call(c, b)
}
replicate(5, foo())

Resources