I've scanned quite some fora on the internet but couldn't find a clear answer to my problem, hence I decided to post it here. The program I am using is R.
The following problem is where I can't seem to find a solution. I am tasked with constructing a vector (1,2,2,3,3,3...,10,...,10) using a nested loop (so no rep()). So far I managed to construct a list of all elements but can't manage to convert it into the desired vector. I have tried quite some methods, like converting the data into a matrix and transposing it etc.
So far not a single method has worked, perhaps someone with more insight on this matter could help me.
This is what I've got so far:
for (i in 1:10){
for (j in 1:10)
if (j<=i)
{
x = c(i)
print(x)
}
}
which provides me with:
[1] 1
[1] 2
[1] 2
[1] 3
[1] 3
[1] 3
[1] 4
[1] 4
[1] 4
[1] 4
[1] 5
[1] 5
[1] 5
[1] 5
[1] 5
[1] 6
[1] 6
[1] 6
[1] 6
[1] 6
[1] 6
[1] 7
[1] 7
[1] 7
[1] 7
[1] 7
[1] 7
[1] 7
[1] 8
[1] 8
[1] 8
[1] 8
[1] 8
[1] 8
[1] 8
[1] 8
[1] 9
[1] 9
[1] 9
[1] 9
[1] 9
[1] 9
[1] 9
[1] 9
[1] 9
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
[1] 10
Thanks in advance!
If storing the result in a vector, instead of printing it, is the remaining problem, this can be done this way:
result <- vector(mode = "integer")
k <- 1
for (i in 1:10){
for (j in 1:10)
if (j<=i)
{
result[k] = c(i)
k <- k+1
}
}
head(result)
Related
I am just practicing basic for loops to compare against their purrr::map() equivalent. However I am lost why the simple print function appears to double the output vs. its equivalent for loop.
#this simple for loop behaves as expected and gives us the numbers 1 through 10.
.x <- 1:10
for (i in .x){
print(i)
}
#result
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
#this doubles the output in an embedded list - I don't understand why
map(.x=.x,~print(.x))
#results below
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 4
[[5]]
[1] 5
[[6]]
[1] 6
[[7]]
[1] 7
[[8]]
[1] 8
[[9]]
[1] 9
[[10]]
[1] 10
I would have though they would produce the same (however I know the map results would be in a list unless I specify the output (eg. map_chr or map_df).
According to R documentations print prints its argument and returns it invisibly (via invisible(x)).
So your map function is essentially doing
.x <- 1:10
funcy <- function() {
out = list()
for (i in .x){
out[[i]] = print(i)
}
return(out)
}
funcy()
The print function gets called every loop and when the loop ends the function returns the stored values in a list
The purrr library has a function specifically designed for tasks such as this: walk.
If you don't want to return anything and are only calling functions for the purpose of their downstream effects (print or write_csv), you can use walk instead of map.
walk(1:10, print)
# [1] 1
# [1] 2
# [1] 3
# [1] 4
# [1] 5
# [1] 6
# [1] 7
# [1] 8
# [1] 9
# [1] 10
I have a list of vectors in R:
test_list <- list()
test_list[[1]] <- c(1,2,3,4,5,6,7)
test_list[[2]] <- c(1,2,3)
test_list[[3]] <- c(6,7)
test_list[[4]] <- c(9,10,11)
And I want to check the intersection of each vector with all the other vectors. A nested loop approach would look like this:
for(i in test_list) {
for(j in test_list) {
intersect(i, j)
}
}
And the results would look like this:
[1] 1 2 3 4 5 6 7
[1] 1 2 3
[1] 6 7
numeric(0)
[1] 1 2 3
[1] 1 2 3
numeric(0)
numeric(0)
[1] 6 7
numeric(0)
[1] 6 7
numeric(0)
numeric(0)
numeric(0)
numeric(0)
[1] 9 10 11
I have seen that I can remove one of the foor loops using map or apply:
get_overlap_cells <- function(x) {
for(i in test_list) {
overlaping_cells <- intersect(i, x)
}
}
r <- map(test_list, get_overlap_cells)
However, I would like to remove both loops, any ideas on how to achieve this?
Thank you!
combins <- expand.grid(seq_along(test_list), seq_along(test_list))
mapply( function(x,y) intersect(test_list[[x]],test_list[[y]]),
combins[,1], combins[,2])
[[1]]
[1] 1 2 3 4 5 6 7
[[2]]
[1] 1 2 3
[[3]]
[1] 6 7
[[4]]
numeric(0)
[[5]]
[1] 1 2 3
[[6]]
[1] 1 2 3
[[7]]
numeric(0)
[[8]]
numeric(0)
[[9]]
[1] 6 7
[[10]]
numeric(0)
[[11]]
[1] 6 7
[[12]]
numeric(0)
[[13]]
numeric(0)
[[14]]
numeric(0)
[[15]]
numeric(0)
[[16]]
[1] 9 10 11
Suppose we have a value y=4, and a list of vectors, I want to check if this value belongs to any vector in the list if yes, I will add this value to all the elements of vectors.
y<-4
M<- list( c(1,3,4,6) , c(2,3,5), c(1,3,6) ,c(1,4,5,6))
> M
[[1]]
[1] 1 3 4 6
[[2]]
[1] 2 3 5
[[3]]
[1] 1 3 6
[[4]]
[1] 1 4 5 6
The outcomes will be similar to :
> R
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
We can use keep which only keeps elements that satisfy a predicate. In this case, it is only keeping the vectors that contain y.
We then add y to each of the vectors.
library('tidyverse')
keep(M, ~y %in% .) %>%
map(~. + y)
Here is a simple hacky way to do this:
lapply(M[sapply(M, function(x){y %in% x})],function(x){x+y})
returning:
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Logic: use sapply to work out which parts of M have a 4 in, then add 4 to those with lapply
You can do this with...
lapply(M[sapply(M, `%in%`, x=y)], `+`, y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Here is a method with lapply and set functions.
# loop through M, check length of intersect
myList <- lapply(M, function(x) if(length(intersect(y, x)) > 0) x + y else NULL)
# now subset, dropping the NULL elements
myList <- myList[lengths(myList) > 0]
this returns
myList
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Wow! everyone has given great answers, just including the use of Map functionality.
Map("+",M[unlist(Map("%in%", y,M))],y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
How to remove outliers using a criterion that a value cannot be more than 2-fold higher then its preceding one.
Here is my try:
x<-c(1,2,6,4,10,20,50,10,2,1)
remove_outliers <- function(x, na.rm = TRUE, ...) {
for(i in 1:length(x))
x < (x[i-1] + 2*x)
x
}
remove_outliers(y)
expected outcome: 1,2,4,10,20,2,1
Thanks!
I think the first 10 should be removed in your data because 10>2*4. Here's a way to do what you want without loops. I'm using the dplyr version of lag.
library(dplyr)
x<-c(1,2,6,4,10,20,50,10,2,1)
x[c(TRUE,na.omit(x<=dplyr::lag(x)*2))]
[1] 1 2 4 20 10 2 1
EDIT
To use this with a data.frame:
df <- data.frame(id=1:10, x=c(1,2,6,4,10,20,50,10,2,1))
df[c(TRUE,na.omit(df$x<=dplyr::lag(df$x,1)*2)),]
id x
1 1 1
2 2 2
4 4 4
6 6 20
8 8 10
9 9 2
10 10 1
A simple sapply:
bool<-sapply(seq_along(1:length(x)),function(i) {ifelse(x[i]<2*x[i-1],FALSE,TRUE)})
bool
[[1]]
logical(0)
[[2]]
[1] TRUE
[[3]]
[1] TRUE
[[4]]
[1] FALSE
[[5]]
[1] TRUE
[[6]]
[1] TRUE
[[7]]
[1] TRUE
[[8]]
[1] FALSE
[[9]]
[1] FALSE
[[10]]
[1] FALSE
resulting in:
x[unlist(bool)]
[1] 1 2 4 10 20 1
How does one go about subsetting lists of lists in R?
For example I have this list:
[[6]]
[[6]][[1]]
[[6]][[1]][[1]]
[1] 111
[[6]][[2]]
[[6]][[2]][[1]]
[1] 1
[[6]][[2]][[2]]
[1] 11
[[6]][[3]]
[[6]][[3]][[1]]
[1] 11
[[6]][[3]][[2]]
[1] 1
[[6]][[4]]
[[6]][[4]][[1]]
[1] 1
[[6]][[4]][[2]]
[1] 1
[[6]][[4]][[3]]
[1] 1
and I'm trying to get all parts of the list that have 2 sublists or less. So in this example the output would be the first five sublists,
[[6]]
[[6]][[1]]
[[6]][[1]][[1]]
[1] 111
[[6]][[2]]
[[6]][[2]][[1]]
[1] 1
[[6]][[2]][[2]]
[1] 11
[[6]][[3]]
[[6]][[3]][[1]]
[1] 11
[[6]][[3]][[2]]
[1] 1
If your list is called lst, then try
lst[lengths(lst) <= 2]