Ordering data.frames elegantly by factor I have a mock_Data:

structure(list(Sample = structure(c(29L, 31L, 21L, 25L, 15L, 
17L, 13L, 27L, 23L), .Label = c("109d0", "109d2", "116d0", "116d2", 
"125d0", "125d2", "136d0", "136d2", "138d0", "138d2", "141d0", 
"141d2", "144d0", "144d2", "18d0", "18d2", "28d0", "28d2", "30d0", 
"30d2", "39d0", "39d2", "4d0", "4d2", "70d0", "70d2", "73d0", 
"73d2", "82d0", "82d2", "83d0", "83d2"), class = "factor"), Clinical = structure(c(1L, 
2L, 1L, 2L, 1L, 2L, 1L, 1L, 2L), .Label = c("low faecal Salmonella shedding", 
"persistent faecal Salmonella shedding"), class = "factor")), .Names = c("Sample", 
"Clinical"), row.names = c(NA, 9L), class = "data.frame")


And I need to reorder it so that the rows with the same Clinical factor are together.

So far I generated this function :

reorder_by_factor &lt;- function(data, factor){
  # Function to get the indices of an unamed rows 
  flev &lt;- levels(factor)
  ac &lt;- function(data, factor, x){
    # Extract rownames
    rownames(data)[with(data, factor == x)]
  }
  ap &lt;- sapply(flev, ac, data = data, factor = factor )
  unlist(ap)
}


that outputs the index of each factor ordered, and I can use it as mock_Data[reorder_by_factor(mock_Data, mock_Data$Clinical),]

I would like to be able to use it like lm with just reorder_by_factor(mock_Data, Clinical) and if possible make it more elegant and general, so it could take several factors and reorder them one, after the other. Also I would like to know which code would broke the function (aside from a data.frame with rownames)
I think the task you are attempting to accomplish (obtain indices to reorder a data frame by several factors, one after another) is already handled well by the built-in order function. Let's consider your sample data:

order(mock_Data$Clinical)
# [1] 1 3 5 7 8 2 4 6 9


As you can see, order is returning row numbers instead of row names; this yields an identical reordered data frame:

identical(mock_Data[reorder_by_factor(mock_Data, mock_Data$Clinical),],
          mock_Data[order(mock_Data$Clinical),])
# [1] TRUE


There are several other advantages of using the built-in order function:


It already smoothly handles reordering by multiple factors, one after another
It can reorder by a mix of factor and numeric variables
It is already implemented and distributed with base R, so you don't need to develop and test your own version of this function


Another advantage is that the built-in order function is more efficient than your implementation. Let's see on a resampled version of your dataset with 1 million rows:

set.seed(144)
big.dat &lt;- mock_Data[sample(seq_len(nrow(mock_Data)), 1e6, replace=T),]
library(microbenchmark)
microbenchmark(reorder_by_factor(big.dat, big.dat$Clinical), order(big.dat$Clinical))
# Unit: milliseconds
#                                          expr      min       lq     mean   median        uq       max neval
#  reorder_by_factor(big.dat, big.dat$Clinical) 562.2527 744.4318 939.0831 898.6288 1054.0008 1678.1246   100
#                       order(big.dat$Clinical) 149.4750 153.2963 199.8178 160.5452  225.9082  459.5558   100


The built-in function runs about 5x faster.