3

I need to sort a data frame by several columns, and I have the name of the columns in a variable. My question is related to this one but in my case the columns to be used to sort are stored in a variable, like in this other question.

I borrow the data frame from the first question:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
dd
    b x y z
1  Hi A 8 1
2 Med D 3 1
3  Hi A 9 1
4 Low C 9 2

What I need to do is sort dd by z decreasing, and by b increasing. The sort answer is:

dd[with(dd, order(-z, b)), ]

What I have is:

sort_list <- c("z","b")

From the second question I know I can do:

dd[do.call(order, dd[, sort_list]),]

But that only gives me increasing order for both variables. What I can't figure out is how to do it with decreasing order. I've tried this:

dd[do.call(order, list(dd[, sort_list]), decreasing = c(TRUE,FALSE)),]

which produces an error, because it's assuming the decreasing argument is just another ordering item.

2
  • 1
    Are you looking for this? require(dplyr) ; dd %>% group_by(b,z) %>% arrange(b,desc(z)) Commented Oct 28, 2016 at 9:19
  • No, sorry. As I say, my column names are stored in a variable, so I don't know them in advance. Commented Oct 28, 2016 at 11:49

3 Answers 3

2

Using data.table order function, you could do :

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
                            levels = c("Low", "Med", "Hi"), ordered = TRUE),
                 x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
                 z = c(1, 1, 1, 2))


library(data.table)
sort_list <- c("z","b")
sort_order <- c(-1, 1)
setDT(dd)
setorderv(dd, sort_list, sort_order)
dd
#>      b x y z
#> 1: Low C 9 2
#> 2: Med D 3 1
#> 3:  Hi A 8 1
#> 4:  Hi A 9 1
Sign up to request clarification or add additional context in comments.

Comments

1

This works:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
sort_list <- c("z","b")
dd[order(-dd[,sort_list[1]], dd[,sort_list[2]]), ]
# or
dd[order(-dd[,sort_list["z"]], dd[,sort_list["b"]]), ]

if that's annoying to type, or the variable names change, or whatever, you could stick it in a function (in right order):

downup <- function(dat, sort_list){
    dat[order(-dat[,sort_list[1]], dat[,sort_list[2]]), ]
}
downup(dd)

That help?

2 Comments

What if you sort by 3 columns ? or other order(asc \desc)?
As @Batanichek says this solution is limited to a very specific situation (two columns first decreasing, second increasing). It would be interesting to have a more general solution. It solves my particular problem though. Thanks.
0

dplyr example

library(dplyr)
sort_list <- c("z","b")
sort_order=c(TRUE,FALSE)
dd %>% arrange_(.dots=ifelse(sort_order,paste0("desc(",sort_list,")"),sort_list))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.