Jon
Jon

Reputation: 455

R Sort one column ascending, all others descending (based on column order)

I have an ordered table, similar to as follows:

df <- read.table(text = 
"A   B   C   Size
1   0   0   1
0   1   1   2
0   0   1   1
1   1   0   2
0   1   0   1",
header = TRUE)

In reality there will be many more columns, but this is fine for a solution.

I wish to sort this table first by SIZE (Ascending), then by each other column in priority sequence (Descending) - i.e. by column A first, then B, then C, etc.

The problem is that I will not know the column names in advance so cannot name them, but need in effect "all columns except SIZE".

End result should be:

A B C Size
1 0 0 1
0 1 0 1
0 0 1 1
1 1 0 2
0 1 1 2

I've seen examples of sorting by two columns, but I just can't find the correct syntax to sort by 'all other columns sequentially'.

Many thanks

Upvotes: 5

Views: 8413

Answers (2)

G. Grothendieck
G. Grothendieck

Reputation: 270248

With the names use order like this. No packages are used.

o <- with(df, order(Size, -A, -B, -C))
df[o, ]

This gives:

  A B C Size
1 1 0 0    1
5 0 1 0    1
3 0 0 1    1
4 1 1 0    2
2 0 1 1    2

or without the names just use column numbers:

o <- order(df[[4]], -df[[1]], -df[[2]], -df[[3]])

or

k <- 4
o <- do.call("order", data.frame(df[[k]], -df[-k]))

If Size is always the last column use k <- ncol(df) instead or if it is not necessarily last but always called Size then use k <- match("Size", names(df)) instead.

Note: Although not needed in the example shown in the question if the columns were not numeric then one could not negate them so a more general solution would be to replace the first line above with the following where xtfrm is an R function which converts objects to numeric such that the result sorts in the order expected.

o <- with(df, order(Size, -xtfrm(A), -xtfrm(B), -xtfrm(C)))

Upvotes: 13

akrun
akrun

Reputation: 887891

We can use arrange from dplyr

library(dplyr)
arrange(df, Size, desc(A), desc(B), desc(C))

For more number of columns, arrange_ can be used

cols <-  paste0("desc(", names(df)[1:3], ")")
arrange_(df, .dots = c("Size", cols))

Upvotes: 5

Related Questions