do.call
needs a list
as arguments to the function call. So you need to split the rows of the matrix into a list. The function asplit
can do this by split an array or matrix by its margins.
mt[,do.call(order, asplit(mt, 1))]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 3 3 3 3
#[2,] 2 1 2 3 3
#[3,] 3 2 2 1 3
#[4,] 1 2 2 1 2
asplit
is currently (4.2.3) doing this by selceting the slices and filling up the list an a for
loop. Other options can be found at converting a matrix to a list or Convert a matrix to a list of column-vectors.
Comparing some possible methods with a larger matrix:
m <- matrix(sample(0:9, 1e6, TRUE), 1e3)
bench::mark(
asplit = m[,do.call(order, asplit(m, 1))],
data.frame = m[, do.call(order, data.frame(t(m)))],
splitRow = m[, do.call(order, split(m, row(m)))],
lapply = m[,do.call(order, lapply(1:nrow(m), function(i) m[i,]))],
splitNrow = m[, do.call(order, split(m, 1:nrow(m)))],
apply = m[, do.call(order, apply(m, 1, identity, simplify = FALSE))],
tapply = m[, do.call(order, tapply(m, row(m), identity))]
)
Result
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:t> <bch:t> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 asplit 8.44ms 9.02ms 111. 19.25MB 73.8 30 20 271ms
2 data.frame 6.88ms 7.24ms 138. 15.47MB 80.3 36 21 261.4ms
3 splitRow 19.79ms 19.98ms 48.9 31.01MB 73.3 10 15 204.6ms
4 lapply 6.79ms 6.99ms 141. 11.57MB 33.8 54 13 384.2ms
5 splitNrow 8.36ms 8.55ms 117. 7.76MB 16.3 50 7 428.8ms
6 apply 7.53ms 7.74ms 128. 15.38MB 50.6 43 17 335.9ms
7 tapply 27.64ms 28.47ms 35.4 38.73MB 165. 3 14 84.7ms
The methods data.frame
and lapply
are the fastest and splitNrow
allocates the lowest amount of additional memory but asplit
is not so far behind and is more general and works also for arrays and allows easy to change the margin.