如何对字母数字字符对象进行排序?

时间:2014-08-20 18:38:30

标签: r

我想使用循环在某些文件上应用函数。我读了一个文件夹中的所有文件:

> tt <- list.files("/PATH.to.FILES/", full.names=TRUE) 
> tt
 [1] /PATH.to.FILES/AA.22.1 
 [2] /PATH.to.FILES/AA.22.10
 [3] /PATH.to.FILES/AA.22.11
 [4] /PATH.to.FILES/AA.22.12
 [5] /PATH.to.FILES/AA.22.13
 [6] /PATH.to.FILES/AA.22.2 
 [7] /PATH.to.FILES/AA.22.3 
 [8] /PATH.to.FILES/AA.22.4 
 [9] /PATH.to.FILES/AA.22.5 
 [10] /PATH.to.FILES/AA.22.6 
 [11] /PATH.to.FILES/AA.22.7 
 [12] /PATH.to.FILES/AA.22.8 
 [13] /PATH.to.FILES/AA.22.9

我想按照文件名中最后一个数字(即22之后的数字)确定的顺序将其传递给循环。目前,如您所见,在1之后,有10, 11, 12, 13。我希望它是这样的:

> tt
[1] /PATH.to.FILES/AA.22.1 
[2] /PATH.to.FILES/AA.22.2 
[3] /PATH.to.FILES/AA.22.3 
[4] /PATH.to.FILES/AA.22.4 
[5] /PATH.to.FILES/AA.22.5 
[6] /PATH.to.FILES/AA.22.6 
[7] /PATH.to.FILES/AA.22.7 
[8] /PATH.to.FILES/AA.22.8 
[9] /PATH.to.FILES/AA.22.9
[10] /PATH.to.FILES/AA.22.10
[11] /PATH.to.FILES/AA.22.11
[12] /PATH.to.FILES/AA.22.12
[13] /PATH.to.FILES/AA.22.13

我尝试了mixedsort(tt),但它没有用。我很感激你的帮助。

5 个答案:

答案 0 :(得分:2)

as.numeric关于将所有内容分到最后一个小数点的结果:

> tt[ order( as.numeric( sub("^.+\\.", "", tt) ) ) ]
 [1] "/PATH.to.FILES/AA.22.1 " "/PATH.to.FILES/AA.22.2 "
 [3] "/PATH.to.FILES/AA.22.3 " "/PATH.to.FILES/AA.22.4 "
 [5] "/PATH.to.FILES/AA.22.5 " "/PATH.to.FILES/AA.22.6 "
 [7] "/PATH.to.FILES/AA.22.7 " "/PATH.to.FILES/AA.22.8 "
 [9] "/PATH.to.FILES/AA.22.9"  "/PATH.to.FILES/AA.22.10"
[11] "/PATH.to.FILES/AA.22.11" "/PATH.to.FILES/AA.22.12"
[13] "/PATH.to.FILES/AA.22.13"

如果你想匹配由点分隔的字符串中的倒数第二项,则会更复杂一些。我已经说明了一种匹配&#34;数字&#34;的可能方法。删除&#39; dot&#39;α结尾之前的字符。

 sub("(^.+\\.)(\\d+)(\\.[A-Z]+$)", "\\2", "AA.BB.$i.2.CC")
 [1] "2"

您需要查找?regex

答案 1 :(得分:1)

这是词典排序,这意味着语言基本上将变量视为字符串并逐字符比较(“200”大于“19999”,因为“2”大于'1')

要解决此问题,您可以

  • 确保将值视为整数;
  • 将前缀'0'添加到字符串中,这样所有字符串都具有相同的长度(只有在知道最大值时才可行)。这就是为什么你会在媒体文件(S1E01)上看到带有前置0的剧集编号的原因,因此词典排序不会弄乱,并允许程序按字母顺序简单地播放/显示;
  • 或制作一个自定义比较器,首先比较字符串的长度(较短的字符串是较小的整数),当它们相等时,按字典顺序比较(小心引导'0')。

答案 2 :(得分:1)

这似乎与mixedsort依赖gsub将数字与字符串隔离开来的事实有关。不幸的是,.gsub的一个特殊字符,他们用来隔离数字的匹配根本不喜欢它!

但是,如果你愿意用mixedsort更喜欢的东西替换所有的点(比如*,例如,这也应该是有风险的,因为它也是一个特殊的角色),它会工作:

x <- c("/PATH.to.FILES/AA.22.1", "/PATH.to.FILES/AA.22.10", "/PATH.to.FILES/AA.22.11", 
"/PATH.to.FILES/AA.22.12", "/PATH.to.FILES/AA.22.13", "/PATH.to.FILES/AA.22.2", 
"/PATH.to.FILES/AA.22.3", "/PATH.to.FILES/AA.22.4", "/PATH.to.FILES/AA.22.5", 
"/PATH.to.FILES/AA.22.6", "/PATH.to.FILES/AA.22.7", "/PATH.to.FILES/AA.22.8", 
"/PATH.to.FILES/AA.22.9")

x_star <- gsub("\\.", "*", x)
sorted_x_star <- gtools::mixedsort(x_star)
sorted_x <-  gsub("\\*", ".", sorted_x_star)

答案 3 :(得分:0)

我确定这是一种更简单的方法,但这是我会立即采取的方法。

tt[order(sapply(strsplit(tt, ".", fixed = TRUE), function(x) as.numeric(x[5])))]

答案 4 :(得分:0)

这是一个应该有效的功能

#sample data
pp<-c("/PATH.to.FILES/AA.22.1", "/PATH.to.FILES/AA.22.10", "/PATH.to.FILES/AA.22.11", 
"/PATH.to.FILES/AA.22.12", "/PATH.to.FILES/AA.22.13", "/PATH.to.FILES/AA.22.2", 
"/PATH.to.FILES/AA.22.3", "/PATH.to.FILES/AA.22.4", "/PATH.to.FILES/AA.22.5", 
"/PATH.to.FILES/AA.22.6", "/PATH.to.FILES/AA.22.7", "/PATH.to.FILES/AA.22.8", 
"/PATH.to.FILES/AA.22.9")

这是我们的排序功能

multiorder <- function(x, seps="[./]") {
    do.call(order, 
        read.table(text=sapply(strsplit(pp, seps), 
    paste, collapse="\t")))
}

测试出来

pp[multiorder(pp)]

#  [1] "/PATH.to.FILES/AA.22.1"  "/PATH.to.FILES/AA.22.2" 
#  [3] "/PATH.to.FILES/AA.22.3"  "/PATH.to.FILES/AA.22.4" 
#  [5] "/PATH.to.FILES/AA.22.5"  "/PATH.to.FILES/AA.22.6" 
#  [7] "/PATH.to.FILES/AA.22.7"  "/PATH.to.FILES/AA.22.8" 
#  [9] "/PATH.to.FILES/AA.22.9"  "/PATH.to.FILES/AA.22.10"
# [11] "/PATH.to.FILES/AA.22.11" "/PATH.to.FILES/AA.22.12"
# [13] "/PATH.to.FILES/AA.22.13"

我们的想法是,我们将/.上的值拆分并处理每一列。我们通过read.table发送它,以便每个&#34;列&#34;转换为正确的数字/字符data.type。然后我们根据所有列进行订购。只要要排序的部分都以某种方式分隔,这将适用于文件名的非常一般的情况。这确实假设所有记录具有相同数量的&#34;虚拟列&#34;。如果不是这种情况,您可能希望将它们共享列并根据它进行排序的部分进行子集化。