这是一个简洁的解决方案:
mat[do.call(order,as.data.frame(mat)),];
## c b a
## [1,] 0 0 0
## [2,] 0 0 1
## [3,] 0 1 0
## [4,] 0 1 1
## [5,] 1 0 0
## [6,] 1 0 1
## [7,] 1 1 0
## [8,] 1 1 1
对as.data.frame() 的调用以直观的方式将矩阵转换为data.frame,即每个矩阵列都成为新data.frame 中的列表组件。由此,您可以通过将矩阵的列表形式作为do.call() 的第二个参数传递,有效地将每个矩阵列传递给order() 的单个调用。
这适用于任意数量的列。
这不是一个愚蠢的问题。 mat[order(as.data.frame(mat)),] 不起作用的原因是order() 确实不按行排序 data.frames。
它不是基于从左到右对列向量进行排序(这是我的解决方案所做的)返回 data.frame 的行顺序,而是基本上将 data.frame 展平为单个大向量并对其进行排序。
所以,事实上,order(as.data.frame(mat)) 等价于order(mat),因为矩阵也被视为平面向量。
对于您的特定数据,这将返回 24 个索引,理论上可用于索引(作为向量)原始矩阵 mat,但由于在表达式 mat[order(as.data.frame(mat)),] 中,您试图使用它们来索引mat 的行维度,一些索引超过了最高行索引,所以会出现“下标越界”错误。
见?do.call。
我认为我不能比帮助页面更好地解释它;看看这些例子,和他们一起玩,直到你知道它是如何工作的。基本上,当您要传递给函数的单个调用的参数被困在列表中时,您需要调用它。
你不能传递列表本身(因为你没有传递预期的参数,你传递的是一个列表包含预期的参数),所以必须有一个原始函数从函数调用列表中“解包”参数。
这是编程语言中常见的原语,其中函数是一等对象,特别是(除了 R 的 do.call())JavaScript 的 apply()、Python 的(已弃用)apply() 和 vim 的 call()。