Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a list of unequal-size vectors in r

Tags:

sorting

r

Suppose I have several vectors - maybe they're stored in a list, but if there's a better data structure that's fine too:

ll <- list(c(1,3,2),
           c(1,2),
           c(2,1),
           c(1,3,1))

And I want to sort them, using the first number, then the second number to resolve ties, then the third number to resolve remaining ties, etc.:

c(1,2)
c(1,3,1)
c(1,3,2)
c(2,1)

Are there any built in functions that will allow me to do this or do I need to roll my own solution?

(For those who know Python, what I'm after is something that mimics the behavior of sort in Python)

like image 417
RobinL Avatar asked Nov 17 '15 12:11

RobinL


2 Answers

ll <- list(c(1,3,2),
           c(1,2),
           c(2,1),
           c(1,3,1))

I'd prefer using NA for missing values and using rbind.data.frame instead of paste:

sortfun <- function(l) {
  l1 <- lapply(l, function(x, n) {
    length(x) <- n
    x
  }, n = max(lengths(l)))
  l1 <- do.call(rbind.data.frame, l1)
  l[do.call(order, l1)] #order's default is na.last = TRUE
}

sortfun(ll)

#[[1]]
#[1] 1 2
#
#[[2]]
#[1] 1 3 1
#
#[[3]]
#[1] 1 3 2
#
#[[4]]
#[1] 2 1
like image 74
Roland Avatar answered Nov 04 '22 21:11

Roland


Here's an approach that uses data.table.

The result is a rectangular data.table with the rows ordered in the form you described. NA values are filled in where the list item was a different length.

library(data.table)
setorderv(data.table(do.call(cbind, transpose(l))), paste0("V", 1:max(lengths(l))))[]
#    V1 V2 V3
# 1:  1  2 NA
# 2:  1  3  1
# 3:  1  3  2
# 4:  2  1 NA

This is ugly, but you can use the result on your list with something like:

l[setorderv(
  data.table(
    do.call(cbind, transpose(l)))[
      , ind := seq_along(l)][], 
  paste0("V", seq_len(max(lengths(l)))))$ind]
like image 44
A5C1D2H2I1M1N2O1R2T1 Avatar answered Nov 04 '22 21:11

A5C1D2H2I1M1N2O1R2T1