【问题标题】:Custom letter ordering with normal numeric ordering in RR中具有正常数字排序的自定义字母排序
【发布时间】:2021-12-30 10:46:52
【问题描述】:

我有一个字符串形式的数据标签列表,就像这样:

data <- c("ABCD 2", "ABCD 3", "WXYZ 1", "WXYZ 5", "WXYZ 3", "WXYZ 4", "ABCD 4", "ABCD 11")

请注意,某些数字(包括“1”)有时会丢失。当然,正常的排序是将ABCD 标签放在WXYZ 标签之前,然后将ABCD 11 放在ABCD 2 之前。

我可以使用gtools::mixedsort 轻松解决编号问题。但是,出于特定问题的上下文的原因,我希望WXYZ 标记位于ABCD 标记之前。

例如,当上面的data按我需要排序时,它应该是这样的:

dataSorted <- c("WXYZ 1", "WXYZ 3", "WXYZ 4", "WXYZ 5", "ABCD 2", "ABCD 3", "ABCD 4", "ABCD 11")

谢天谢地,我现在只需要处理这两种类型的标签,但我想我应该寻求一个通用的解决方案。有没有办法让gtools::mixedsort 做反向字母但正常的数字排序?如果我设置decreasing = TRUE,那么它也会反转所有的数字顺序。

现在我只是用一个列表来强制排序,这不仅不优雅,而且由于标签上的数字没有理论上的上限,它最终也会被打破。

【问题讨论】:

    标签: r sorting


    【解决方案1】:

    我们可以分别提取数字和非数字,然后在转换为factor 后做order 并为非数字部分指定levels

    data[order(factor(sub("\\s+\\d+", "", data), 
       levels = c("WXYZ", "ABCD")), as.integer(sub("\\S+\\s+", "", data)))]
    

    -输出

    [1] "WXYZ 1"  "WXYZ 3"  "WXYZ 4"  "WXYZ 5" 
    [5] "ABCD 2"  "ABCD 3"  "ABCD 4"  "ABCD 11"
    

    【讨论】:

    • 这看起来很完美。我要等一会儿来尝试应用它(厨房里有很多厨师),但如果它有效,我会接受它!谢谢!
    【解决方案2】:

    这无需任何预定义或手动输入数据即可工作。 唯一的先决条件是第一项必须是字母字符串,第二项必须是数字(如果缺少数字,则引入 NA)。

    首先,用 空格 分割字符串,然后按字母分组,然后对组内的数字进行排序。 然后必须将两者重新组合在一起。

    # split
    dat <- setNames( data.frame( t(data.frame( strsplit( data, " " ) )[1,]),
      as.numeric( data.frame( strsplit( data, " " ) )[2,]) ), c("A","B") )
    #                   A  B
    #c..ABCD....2..  ABCD  2
    #c..ABCD....3..  ABCD  3
    #c..WXYZ....1..  WXYZ  1
    #c..WXYZ....5..  WXYZ  5
    #c..WXYZ....3..  WXYZ  3
    #c..WXYZ....4..  WXYZ  4
    #c..ABCD....4..  ABCD  4
    #c..ABCD....11.. ABCD 11
    
    # group and order
    dat_agr <- aggregate( B ~ A, dat, na.action=na.pass, 
      function(x)sort(x, na.last=T), simplify=F )
    dat_ord <- dat_agr[order(dat_agr[,"A"], decreasing=T),]
    #     A           B
    #2 WXYZ  1, 3, 4, 5
    #1 ABCD 2, 3, 4, 11
    
    # bring back together
    unlist(lapply( dat_ord$A, function(x) sapply( 
      dat_ord[grep(x, dat_ord$A),"B"], function(y) paste(x,y) ) ))
    [1] "WXYZ 1"  "WXYZ 3"  "WXYZ 4"  "WXYZ 5"  "ABCD 2"  "ABCD 3"  "ABCD 4" 
    [8] "ABCD 11"
    

    【讨论】:

      猜你喜欢
      • 2017-06-13
      • 2013-10-15
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      • 1970-01-01
      • 1970-01-01
      • 2014-06-14
      相关资源
      最近更新 更多