PAYATHON 2026

如何在 R 中对 data.table 每行的数值升序排序并保持行顺序?

数据小陈

可以先将 data.table 转成数值矩阵,再用 apply(..., 1L, sort) 对每行排序,最后转置并转回 data.table。排序只改变行内数值的位置,不改变行的先后顺序。

对每一行执行升序排序

对于题目中有数据行、至少两列且所有列都是普通数值的表,可以直接使用:

library(data.table)

result <- as.data.table(
  t(apply(as.matrix(data), 1L, sort, na.last = TRUE))
)
setnames(result, names(data))

apply 的第二个参数 1L 表示按行处理,sort 默认按升序排序。apply 会把每行的排序结果作为返回矩阵的一列,因此需要用 t() 转置,恢复原来的行列方向。

setnames 保留原来的列名。排序后,各列表示该行数值从小到大的位置,原来数值与列名的对应关系不再保留。

可直接运行的示例

原始 dput 内容中的 <pointer: ...> 是指针的打印表示,不能直接作为 R 代码执行。可以用 fread 重建示例数据:

library(data.table)

data <- fread("20 1 54 5 55 33
2 48 20 28 6 3
7 23 4 6 55 40
20 56 51 6 22 3
48 28 55 52 38 15
12 11 30 42 10 33", sep = " ", header = FALSE)

result <- as.data.table(
  t(apply(as.matrix(data), 1L, sort, na.last = TRUE))
)
setnames(result, names(data))

result

排序结果为:

      V1    V2    V3    V4    V5    V6
1:     1     5    20    33    54    55
2:     2     3     6    20    28    48
3:     4     6     7    23    40    55
4:     3     6    20    22    51    56
5:    15    28    38    48    52    55
6:    10    11    12    30    33    42

为什么 arrange 和 setorder 不适用

dplyr::arrange 和 data.table::setorder 根据指定列的值重新排列整行。例如,按 V1 排序会改变行的先后顺序,但每行的数值仍留在原来的列中。

要对行内数值排序,需要分别对每一行执行 sort。

类型和缺失值注意事项

  • na.last = TRUE 会保留 NA,并将其放在每行末尾。sort 默认会移除缺失值,可能导致各行排序后的长度不同。
  • 参与排序的列应全部是普通数值列。如果混入字符列,as.matrix 可能把整个矩阵转换为字符,排序也会变成字符顺序。
  • 原示例中的 <num> 表示 double,预期结果中的 <int> 表示 integer。数值排列相同并不意味着存储类型相同;排序本身不要求将 double 转成 integer。
  • 上面的简洁写法适用于至少两列且有数据行的情况。单列数据无需进行行内排序,空表也可以直接保留。

转换矩阵和生成结果都会占用额外内存。如果数据量很大,应结合表的大小评估内存开销,不能仅凭行数判断性能。

备注:内容仅供参考。