Say I have a list of vectors like this:
list.of.vec <- data.frame(id = c(1,2,3,4)) %>%
mutate(a = list(list(c(1,2,3), c(2,3,4)), list(c(2,4,5), c(1,3,4)), list(c(1,2,3), c(4,3,4)), list(c(3,2,3), c(2,3,4))))
how can I arrange a such that in each pair of vectors, the one with the bigger first values goes first? E.g., if there was a list c(1,2,3), c(2,3,4), it should become c(2,3,4), c(1,2,3). And if first values are equal then it looks at the next value.
We can use rrapply
library(rrapply)
library(purrr)
library(dplyr)
list.of.vec <- list.of.vec %>%
mutate(a = map(a, ~ .x[order(-rrapply(.x, f = function(x) x[1],
how = 'unlist'))]))
-output
> list.of.vec
id a
1 1 2, 3, 4, 1, 2, 3
2 2 2, 4, 5, 1, 3, 4
3 3 4, 3, 4, 1, 2, 3
4 4 3, 2, 3, 2, 3, 4
> list.of.vec$a
[[1]]
[[1]][[1]]
[1] 2 3 4
[[1]][[2]]
[1] 1 2 3
[[2]]
[[2]][[1]]
[1] 2 4 5
[[2]][[2]]
[1] 1 3 4
[[3]]
[[3]][[1]]
[1] 4 3 4
[[3]][[2]]
[1] 1 2 3
[[4]]
[[4]][[1]]
[1] 3 2 3
[[4]][[2]]
[1] 2 3 4
You can use -
list.of.vec$a <- lapply(list.of.vec$a, function(x) {
inds <- match(TRUE, x[[1]] != x[[2]])
if(x[[1]][inds] > x[[2]][inds]) x else rev(x)
})
list.of.vec$a
#[[1]]
#[[1]][[1]]
#[1] 2 3 4
#[[1]][[2]]
#[1] 1 2 3
#[[2]]
#[[2]][[1]]
#[1] 2 4 5
#[[2]][[2]]
#[1] 1 3 4
#[[3]]
#[[3]][[1]]
#[1] 4 3 4
#[[3]][[2]]
#[1] 1 2 3
#[[4]]
#[[4]][[1]]
#[1] 3 2 3
#[[4]][[2]]
#[1] 2 3 4
inds would return the index for each list that we need to compare, an index where the value is different in both the vectors. If the first index has a higher value we return the list as it is without any change or else we return the reversed list.
We can try
lapply(
a,
function(x) {
x[order(-sapply(x, `[`, 1))]
}
)
which gives
[[1]]
[[1]][[1]]
[1] 2 3 4
[[1]][[2]]
[1] 1 2 3
[[2]]
[[2]][[1]]
[1] 2 4 5
[[2]][[2]]
[1] 1 3 4
[[3]]
[[3]][[1]]
[1] 4 3 4
[[3]][[2]]
[1] 1 2 3
[[4]]
[[4]][[1]]
[1] 3 2 3
[[4]][[2]]
[1] 2 3 4
I'm looking for a more efficient way to get from my current input to my expected output.
Input
vec <- 1:4
Expected output
[[1]]
[1] 1 2 3 4
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 3
[[5]]
[1] 4
Current solution:
lis <- list()
lis[2:5] <- as.list(vec)
lis[[1]] <- vec
We can do
c(list(vec), as.list(vec))
#[[1]]
#[1] 1 2 3 4
#[[2]]
#[1] 1
#[[3]]
#[1] 2
#[[4]]
#[1] 3
#[[5]]
#[1] 4
What is the most elegant way to split a vector into n-Elements based on a condition?
Every separate true-block should go into its own list element. All the false elements get thrown away.
example1:
vec <- c(1:3,NA,NA,NA,4:6,NA,NA,NA,7:9,NA)
cond <- !is.na(vec)
result = list(1:3,4:6,7:9)
example2:
vec_2 <- c(3:1,11:13,6:4,14:16,9:7,20)
cond_2 <- vec_2 < 10
results_2 = list(3:1,6:4,9:7)
It would be great to have a general solution for a vector vec and a relating condition cond.
My best try:
res <- split(vec,data.table::rleidv(cond))
odd <- as.logical(seq_along(res)%%2)
res[if(cond[1])odd else !odd]
I guess this should work generally:
> split(vec[cond], data.table::rleid(cond)[cond])
$`1`
[1] 1 2 3
$`3`
[1] 4 5 6
$`5`
[1] 7 8 9
Let's make it a function:
> f <- function(vec, cond) split(vec[cond], data.table::rleid(cond)[cond])
> f(vec_2, cond_2)
$`1`
[1] 3 2 1
$`3`
[1] 6 5 4
$`5`
[1] 9 8 7
Here is a base R option with rle
grp <- with(rle(cond), rep(seq_along(values) * NA^ !values, lengths))
split(vec[cond], grp[cond])
#$`1`
#[1] 1 2 3
#$`3`
#[1] 4 5 6
#$`5`
#[1] 7 8 9
Similarly with 'vec_2'
grp <- with(rle(cond_2), rep(seq_along(values) * NA^ !values, lengths))
split(vec_2[cond_2], grp[cond_2])
#$`1`
#[1] 3 2 1
#$`3`
#[1] 6 5 4
#$`5`
#[1] 9 8 7
Or create a grouping variable with cumsum and diff
grp <- cumsum(c(TRUE, diff(cond) < 0)) * NA^ is.na(vec)
I have a list of vectors
l = list(c(1,2),c(3,4),c(2,3),c(7,8),c(5,6))
and would to reverse sort it by the vector maximums:
> l
[[1]]
[1] 7 8
[[2]]
[1] 5 6
[[3]]
[1] 3 4
[[4]]
[1] 2 3
[[5]]
[1] 1 2
Any idea how I could do this in a one liner? thx
One way is
l[order(sapply(l, max), decreasing=TRUE)]
#[[1]]
#[1] 7 8
#[[2]]
#[1] 5 6
#[[3]]
#[1] 3 4
#[[4]]
#[1] 2 3
#[[5]]
#[1] 1 2
You could replace sapply(l, max) with vapply(l, max, numeric(1L)) as well.
Or a compact form suggested by #DavidArenburg
l[order(-sapply(l, max))]
how do I get the x value of each element in the list.
example:
list1 <- list(1:3,4:6)
list1
#[[1]]
#[1] 1 2 3
#
#[[2]]
#[1] 4 5 6
Imaginary function I'm looking for:
function(list1, 1)
# [1] 1 4
function(list2, 2)
# [1] 2 5
How can I do this?
Use sapply or lapply, in combination with the [ extraction function (see ?Extract for more info) like so:
> sapply(list1,"[",1)
[1] 1 4
...or with a list output:
> lapply(list1,"[",1)
[[1]]
[1] 1
[[2]]
[1] 4