Reverse sort list by max element - r

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))]

Related

R arrange list of vectors

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

Convert each row of dataframe to new list in R

I have below sample input data-
> df <- data.frame(a=c(1,2,9),b=c(3,4,5),c=c(2,6,7))
> df
a b c
1 1 3 2
2 2 4 6
3 9 5 7
I am trying to convert rach row into separate list.
My Attempt-
> apply(df,1,as.list)
The above solution converts each row into sublists. But, I am looking for 3 separate list in this case.
nrow(df) = no. of lists
Desired Output-
> list1
$a
[1] 1
$b
[1] 3
$c
[1] 2
> list2
$a
[1] 2
$b
[1] 4
$c
[1] 6
> list3
$a
[1] 9
$b
[1] 5
$c
[1] 7
You can use by and as.list
out <- by(df, 1:nrow(df), as.list)
out
#1:nrow(df): 1
#$a
#[1] 1
#
#$b
#[1] 3
#$c
#[1] 2
#------------------------------------------------------------------------------
#1:nrow(df): 2
#$a
#[1] 2
#$b
#[1] 4
#$c
#[1] 6
#------------------------------------------------------------------------------
#1:nrow(df): 3
#$a
#[1] 9
#$b
#[1] 5
#$c
#[1] 7
That creates an object of class by. So you may call unclass(out) in the end.

Convert a vector into a specialised list efficiently

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

Replacing values in a list based on a condition

I have a list of values called squares and would like to replace all values which are 0 to a 40.
I tried:
replace(squares, squares==0, 40)
but the list remains unchanged
If it is a list, then loop through the list with lapply and use replace
squares <- lapply(squares, function(x) replace(x, x==0, 40))
squares
#[[1]]
#[1] 40 1 2 3 4 5
#[[2]]
#[1] 1 2 3 4 5 6
#[[3]]
#[1] 40 1 2 3
data
squares <- list(0:5, 1:6, 0:3)
I think for this purpose, you can just treat it as if it were a vector as follows:
squares=list(2,4,6,0,8,0,10,20)
squares[squares==0]=40
Output:
[[1]]
[1] 2
[[2]]
[1] 4
[[3]]
[1] 6
[[4]]
[1] 40
[[5]]
[1] 8
[[6]]
[1] 40
[[7]]
[1] 10
[[8]]
[1] 20

Splitting numeric vectors in R

If I have a vector, c(1,2,3,5,7,9,10,12)...and another vector c(3,7,10), how would I produce the following:
[[1]]
1,2,3
[[2]]
5,7
[[3]]
9,10
[[4]]
12
Notice how 3 7 and 10 become the last number of each list element (except the last one). Or in a sense the "breakpoint". I am sure there is a simple R function I am unknowledgeable of or having loss of memory.
Here's one way using cut and split:
split(x, cut(x, c(-Inf, y, Inf)))
#$`(-Inf,3]`
#[1] 1 2 3
#
#$`(3,7]`
#[1] 5 7
#
#$`(7,10]`
#[1] 9 10
#
#$`(10, Inf]`
#[1] 12
Could do
split(x, cut(x, unique(c(y, range(x)))))
## $`[1,3]`
## [1] 1 2 3
## $`(3,7]`
## [1] 5 7
## $`(7,10]`
## [1] 9 10
## $`(10,12]`
## [1] 12
Similar to #beginneR 's answer, but using findInterval instead of cut
split(x, findInterval(x, y + 1))
# $`0`
# [1] 1 2 3
#
# $`1`
# [1] 5 7
#
# $`2`
# [1] 9 10
#
# $`3`
# [1] 12

Resources