eindzl
eindzl

Reputation: 143

How to sort a dataframe by columns giving column names as a variable

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.

Upvotes: 3

Views: 124

Answers (3)

Batanichek
Batanichek

Reputation: 7871

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

Upvotes: 0

cderv
cderv

Reputation: 6552

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

Upvotes: 2

tim riffe
tim riffe

Reputation: 5691

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?

Upvotes: 1

Related Questions