代码之家  ›  专栏  ›  技术社区  ›  Oscar Kjell

删除字符串中的重复对

r
  •  1
  • Oscar Kjell  · 技术社区  · 8 年前

    在字符串变量中,我希望删除重复项的两部分,以便只选择唯一的字符串。即:

    我有根绳子

    MyString <- c("aaa", "bbb", "ccc", "ddd", "aaa", "ddd") 
    

    我想删除两个副本,然后选择:

    [1] "bbb" "ccc"
    

    运气不好,我试过:

     unique((MyString)
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   moodymudskipper    8 年前
    x <- table(MyString)
    names(x[x==1])
    [1] "bbb" "ccc"
    

    也:

    MyString[ !duplicated(MyString) & !duplicated(MyString,fromLast = T) ]
    [1] "bbb" "ccc"
    
        2
  •  2
  •   Martin Morgan    8 年前

    查找重复项集

    dups = MyString[ duplicated(MyString) ]
    

    并删除集合中的所有事件

    MyString[ !MyString %in% dups ]
    

    备选方案:

    setdiff(MyString, dups)
    

    @moody_mudskipper基于表的解决方案提供了更多的灵活性,例如,选择出现两次的字符串。另一种选择(可能比但类似于 table() -解决方案,何时 MyString 是long),在唯一字符串中创建索引,查找每个唯一字符串匹配的次数( tabulate() == 1 )并使用这些设置唯一字符串的子集:

    UString = unique(MyString)
    UString[ tabulate(match(MyString, UString)) == 1 ]
    

    或者省去创建 UString

    MyString[ which(tabulate(match(MyString, MyString)) == 1) ]
    

    备选方案:排序,然后查找长度为1的管路。

    r = rle(sort(MyString))
    r$values[ r$lengths == 1 ]
    

    为了提高性能,下面是一些实现各种解决方案的函数

    f0 = function(x) x[ !x %in% x[duplicated(x)] ]
    f1 = function(x) setdiff( x, x[duplicated(x)] )
    f2 = function(x) { ux = unique(x); ux[ tabulate(match(x, ux)) == 1 ] }
    f3 = function(x) x[ which( tabulate( match(x, x) ) == 1 ) ]
    f4 = function(x) { r = rle(sort(x)); r$values[ r$lengths == 1] }
    f5 = function(x) { x = table(x); names(x)[x==1] }
    f6 = function(x) x[ !duplicated(x) & !duplicated(x, fromLast = TRUE) ]
    

    它们产生相同结果的证据

    > identical(f0(x), f1(x))
    [1] TRUE
    > identical(f0(x), f2(x))
    [1] TRUE
    > identical(f0(x), f3(x))
    [1] TRUE
    > identical(f0(x), f4(x))
    [1] TRUE
    > identical(f0(x), f5(x))
    [1] TRUE
    > identical(f0(x), f6(x))
    [1] TRUE
    

    f5() (也是最初的实施)失败 x = character(0)

    > f1(character(0))
    character(0)
    > f5(character(0))
    NULL
    

    f4() 和 F5() 返回按字母顺序排列的值,而其他值保留输入中的顺序,如 unique() . 所有方法,但 F5() 使用其他类型的向量,例如, integer() ( 总是返回一个字符向量,其他的返回一个与输入类型相同的向量)。 F4() 和 F5() 不识别 NA .

    时间安排:

    > microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x))
    Unit: microseconds
      expr     min       lq      mean   median       uq      max neval
     f0(x)   9.195  10.9730  12.35724  11.8120  13.0580   29.100   100
     f1(x)  20.471  22.6625  50.15586  24.6750  25.9915 2600.307   100
     f2(x)  13.708  15.2265  58.58714  16.8180  18.4685 4180.829   100
     f3(x)   7.533   8.8775  52.43730   9.9855  11.0060 4252.063   100
     f4(x)  74.333  79.4305 124.26233  83.1505  87.4455 4091.371   100
     f5(x) 147.744 154.3080 196.05684 158.4880 163.6625 3721.522   100
     f6(x)  12.458  14.2335  58.11869  15.4805  17.0440 4250.500   100
    

    这是10000个单词的表演

    > x = readLines("/usr/share/dict/words", 10000)
    > microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x), times = 10)
    Unit: microseconds
      expr       min        lq       mean    median        uq       max neval
     f0(x)   848.086   871.359   880.8841   873.637   899.669   916.528    10
     f1(x)  1440.904  1460.704  1556.7154  1589.405  1607.048  1640.347    10
     f2(x)  2143.997  2257.041  2288.1878  2288.329  2334.494  2372.639    10
     f3(x)  1420.144  1548.055  1547.8093  1562.927  1596.574  1601.176    10
     f4(x) 11829.680 12141.870 12369.5407 12311.334 12716.806 12952.950    10
     f5(x) 15796.546 15833.650 16176.2654 15858.629 15913.465 18604.658    10
     f6(x)  1219.036  1356.807  1354.3578  1363.276  1372.831  1407.077    10
    

    大量重复

    > x = sample(head(x, 1000), 10000, TRUE)
    > microbenchmark(f0(x), f1(x), f2(x), f3(x), f4(x), f5(x), f6(x))
    Unit: milliseconds
      expr       min        lq      mean    median        uq       max neval
     f0(x)  1.914699  1.922925  1.992511  1.945807  2.030469  2.246022   100
     f1(x)  1.888959  1.909469  2.097532  1.948002  2.031083  5.310342   100
     f2(x)  1.396825  1.404801  1.447235  1.420777  1.479277  1.820402   100
     f3(x)  1.248126  1.257283  1.295493  1.285652  1.329139  1.427220   100
     f4(x) 24.075280 24.298454 24.562576 24.459281 24.700579 25.752481   100
     f5(x)  4.044137  4.120369  4.307893  4.174639  4.283030  7.740830   100
     f6(x)  1.221024  1.227792  1.264572  1.243201  1.295888  1.462007   100
    

    f0() 当副本很少时,似乎是速度的赢家

    > x = readLines("/usr/share/dict/words", 100000)
    > microbenchmark(f0(x), f1(x), f3(x), f6(x))
    Unit: milliseconds
      expr      min       lq     mean   median       uq      max neval
     f0(x) 11.03298 11.17124 12.17688 11.36114 11.62769 19.83124   100
     f1(x) 21.16154 21.33792 22.76237 21.67234 22.26473 31.99544   100
     f3(x) 21.15801 21.49355 22.60749 21.77821 22.54203 31.17288   100
     f6(x) 18.72260 18.97623 20.29060 19.46875 19.94892 28.17551   100
    

    f3() 和 f6() 看起来正确快速; F6() 可能更容易理解(但只处理只出现一次的单词的特殊情况)。