假设我有
arr = 2 1 3
1 2 3
1 1 2
如何将这个排序成下面的形式?
arr = 1 1 2
1 2 3
2 1 3
也就是说,首先按照第一列排序,然后按照第二列排序,以此类推。
order
(我是如何得出这个结论的——我的第一反应是“排序,那什么排序?”。试了一下sort(arr)
,看起来是将arr
作为向量进行排序而不是逐行排序。查看?sort
,我看到在“相关信息”:“order
用于对单个或多个变量进行排序或重新排序。”)?order
,我看到order(x,y,z,...)
会按照x排序,通过y打破平局,进一步通过z打破平局等。太棒了 - 我只需要传入arr
的每一列到order
函数就行了。(甚至在?order
示例部分有一个例子):order( arr[,1], arr[,2], arr[,3] )
# gives 3 2 1: row 3 first, then row 2, then row 1.
# Hence:
arr[ order( arr[,1], arr[,2], arr[,3] ), ]
# [,1] [,2] [,3]
#[1,] 1 1 2
#[2,] 1 2 3
#[3,] 2 1 3
太棒了!
但是我必须为arr
中的每一列写出 arr[,i]
- 如果我不知道它有多少列会有点烦人。
好吧,示例也展示了如何解决这个问题:使用do.call
。基本上,你需要:
do.call( order, args )
其中args
是一个包含参数的列表,用于order
函数。因此,如果您可以将arr
的每一列转换成一个列表,那么您就可以将其作为args
使用。
一种方法是将arr
转换为数据帧,然后再转换为列表--这将自动将每个元素放入列表中的一列:
arr[ do.call( order, as.list(as.data.frame(arr)) ), ]
as.list(as.data.frame()
有点笨拙-当然还有其他方法可以创建一个列表,使得list [[i]]
是arr
的第i
列,但这只是其中之一。
arr[do.call(order, lapply(1:NCOL(arr), function(i) arr[, i])), ]
它所做的是:
arr[order(arr[, 1], arr[, 2], arr[ , 3]), ]
除此之外,它允许矩阵中任意数量的列。
我写了一个小函数,可以按降序排列。cols参数允许选择要排序的列和它们的顺序。
ord.mat = function(M, decr = F, cols = NULL){
if(is.null(cols))
cols = 1: ncol(M)
out = do.call( "order", as.data.frame(M[,cols]))
if (decr)
out = rev(out)
return(M[out,])
}
我也遇到了类似的问题,解决方案看起来很简单而且优雅:
t(apply(t(yourMatrix),2,sort))
arr = matrix(c(1, 1, 1, 1, 1, 1, 3, 2, 1), nrow=3)
。 - David Robinson