【问题标题】:Concatenate vector elements in groups连接组中的向量元素
【发布时间】:2013-04-30 17:48:16
【问题描述】:

list1 转换为list2 以及将list2 转换为list1 的最优雅的方式是什么?

list1<- c('a','b','c','d','e','f','g','h','i')
list2<- c('abc','def','ghi')

即:以三人一组的方式接触元素。

谢谢:D

【问题讨论】:

    标签: r vector concatenation grouping


    【解决方案1】:

    1) 试试这个:

    apply(matrix(list1, 3), 2, paste, collapse = "")
    

    2) 和一个即使list1 的长度不是 3 的倍数也能工作的变体。这里3 * ceiling(n/3)m 的长度,我们从中减去n 以获得位置数仍有待填补:

    n <- length(list1)
    k <- 3 * ceiling(n / 3) - n
    m <- matrix(c(list1, rep("", k)), 3)
    apply(m, 2, paste, collapse = "")
    

    3) 这是一个不同的解决方案,如果 n 不是 3 的倍数,这里的第二个解决方案也可以工作:

    n <- length(list1)
    tapply(list1, c(gl(n, 3, n)), paste, collapse = "")
    

    更新:添加了处理长度不是 3 的倍数的变体以及不同的解决方案。

    【讨论】:

    • 这是您对任何n 的第一个解决方案的扩展:apply(matrix(c(list1, rep("", 3 - length(list1) %% 3)), 3), 2, paste, collapse = "")。您应该对此进行基准测试 - 在一些基本测试中看起来非常快。
    • 轻微修正:apply(matrix(c(list1, rep("", (3 - length(list1) %% 3) %% 3)), 3), 2, paste, collapse = "")(也许有人可以想出一个更紧凑的公式,但想法是用适当数量的空单元格填充初始列表)
    • 我在我的帖子中添加了一些长凳 - 这非常适合
    • 添加了第一个解决方案的变体,不需要 n 是 3 的倍数。
    • :) 请注意为什么您不想使用我的建议来计算 k,因为您当前的公式较长且计算效率较低。
    【解决方案2】:

    这是另一个版本,它比@Arun 的两种方法都快(与他的方法 1 相比,imo 以牺牲可读性为代价,不幸的是,这比他的方法 2 慢得多)[编辑: 经过一些基准测试后,它似乎是 Arun 的第一种方法,虽然在中小型尺寸上表现不佳,但实际上可以很多更好地扩展,在较大尺寸下获胜] [[另一个编辑: Grothendieck 解决方案是另一种在小尺寸上表现不佳,但比 Arun 的第一种方法更好的扩展方案]]:

    substring(paste(list1, collapse = ""),
              seq(1, length(list1), 3),
              pmin(seq(3, length(list1)+2, 3), length(list1)))
    

    基准测试

    list1 = sample(letters, 10000, replace = T)
    microbenchmark(eddi=substring(paste(list1, collapse = ""),seq(1, length(list1), 3),pmin(seq(3, length(list1)+2, 3), length(list1))),
                   Arun1=sapply(split(list1, (seq_along(list1)-1) %/% 3), paste, collapse = ""),
                   Arun2=strsplit(paste(list1, collapse=""), pattern, perl=TRUE)[[1]],
                   Grothendieck=apply(matrix(c(list1, rep("", (3 - length(list1) %% 3) %% 3)), 3), 2, paste, collapse = ""),
                   times = 100)
    #Unit: milliseconds
    #         expr       min       lq   median       uq      max neval
    #         eddi  8.804764 10.17807 11.33133 11.58993 12.69495   100
    #        Arun1 51.287326 61.74937 65.51151 67.15510 73.98805   100
    #        Arun2 12.305300 13.52000 14.65123 15.00816 17.20151   100
    # Grothendieck 25.043657 29.15488 29.87843 31.02118 45.85889   100
    

    基准测试继续 这有点有趣,在 1e5 处,Arun1 实际上略微超越了其他两个:

    list1 = sample(letters, 1e5, replace = T)
    microbenchmark(eddi=substring(paste(list1, collapse = ""),seq(1, length(list1), 3),pmin(seq(3, length(list1)+2, 3), length(list1))),
                   Arun1=sapply(split(list1, (seq_along(list1)-1) %/% 3), paste, collapse = ""),
                   Arun2=strsplit(paste(list1, collapse=""), pattern, perl=TRUE)[[1]],
                   Grothendieck=apply(matrix(c(list1, rep("", (3 - length(list1) %% 3) %% 3)), 3), 2, paste, collapse = ""),
                   times = 30)
    #Unit: milliseconds
    #         expr      min       lq   median       uq      max neval
    #         eddi 417.5631 452.6823 480.4397 528.6187 681.0612    30
    #        Arun1 363.0641 401.6795 420.8844 475.2225 587.3645    30
    #        Arun2 426.9462 466.5132 506.1106 552.9374 778.7303    30
    # Grothendieck 178.2272 206.0161 216.2643 246.3848 280.7988    30
    

    大 N 板凳

    list1 = sample(letters, 1e6, replace = T)
    microbenchmark(Arun1=sapply(split(list1, (seq_along(list1)-1) %/% 3), paste, collapse = ""),
    +              Grothendieck=apply(matrix(c(list1, rep("", (3 - length(list1) %% 3) %% 3)), 3), 2, paste, collapse = ""), times = 10)
    #Unit: seconds
    #         expr      min       lq   median       uq      max neval
    #        Arun1 5.829132 7.654288 8.582664 8.779793 9.168519    10
    # Grothendieck 3.196645 3.416421 3.533622 3.725822 3.951419    10
    

    【讨论】:

    • Arun1 在我的情况下似乎是最快的......当我尝试使用 1e5 时。
    • 我也用基准更新了我的帖子。对于您的数据,所有这些都需要大约 37 毫秒。您可以尝试将数据增加到 1e5 并尝试相同的基准测试吗?并且请至少运行 3 次! :) 从我的基准测试看来,正则表达式解决方案method2(最慢的)与您的解决方案非常匹配。
    • Arun1?真的吗?如果它是非线性的,那就很有趣了
    • 在我的基准测试中,唯一似乎可以很好地扩展的是sapply 解决方案。正如@flodel 所写,可以用tapply (sapply+split) 代替。
    • @Arun,我看到了类似的东西 - 太好了,如果更优雅的解决方案在基准测试中获胜,我总是很高兴 :)
    【解决方案3】:

    list1 &lt;- letters[1:10](展示当向量的长度不是 3 的倍数时它是如何工作的)。然后,试试这个:

    list1 到 list2

    # method 1 (seems to be the fastest so far, 
    # my suspicions about loop being slower were wrong)
    list2 <- sapply(split(list1, (seq_along(list1)-1) %/% 3), paste, collapse = "")
    # alternatively as @flodel mentions
    list2 <- tapply(list1, (seq_along(list1)-1) %/% 3, paste, collapse = "")
    

    tapply 版本与sapply+split 的运行时间相似(未显示基准测试)。

    更进一步,使用@JoshOBrien 在this post 中的想法

    # method 2
    pattern <- "(?<=[[:alnum:]]{3})(?=[[:alnum:]])"
    strsplit(paste(list1, collapse=""), pattern, perl=TRUE)[[1]]
    # [1] "abc" "def" "ghi" "j"  
    

    如果您想将最后一部分连接到最后一个部分(这里是 jghi),那么,请执行以下操作:

    pattern <- "(?<=[[:alnum:]]{3})(?=[[:alnum:]]{3})"
    strsplit(paste(list1, collapse=""), pattern, perl=TRUE)[[1]]
    # [1] "abc"  "def"  "ghij"
    

    list2 到 list1

    unlist(strsplit(list2, ""), use.names=FALSE)
    #  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
    

    这是method1method2 和 eddi 的基准测试:

    数据:

    list1 <- sample(letters, 1e5, replace=TRUE)
    

    功能:

    arun <- function() {
        pattern <- "(?<=[[:alnum:]]{3})(?=[[:alnum:]])"
        strsplit(paste(list1, collapse=""), pattern, perl=TRUE)[[1]]
    }
    
    arun2 <- function() {
        unname(sapply(split(list1, (seq_along(list1)-1) %/% 3), paste, collapse = ""))
    }
    
    eddi <- function() {
        substring(paste(list1, collapse = ""),
              seq(1, length(list1), 3),
              pmin(seq(3, length(list1)+2, 3), length(list1)))    
    }
    

    基准测试:

    require(microbenchmark)
    microbenchmark(t1 <- arun(), t2 <- eddi(), t3 <- arun2(), times=10)
    identical(t1, t2) # TRUE
    identical(t1, t3) # TRUE
    
    # Unit: milliseconds
    #           expr       min        lq    median        uq       max neval
    #   t1 <- arun() 3352.9867 3400.8627 3512.7037 3585.6499 3635.2182    10
    #   t2 <- eddi() 3302.0925 3318.4184 3356.2109 3409.9728 3487.7220    10
    #  t3 <- arun2()  474.9235  494.7407  539.4406  641.2605  907.9072    10
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 2013-12-21
      • 2021-09-12
      • 1970-01-01
      • 2017-12-30
      • 2011-11-03
      • 1970-01-01
      相关资源
      最近更新 更多