连接组中的矢量元素

时间:2013-05-06 21:43:48

标签: r vector concatenation grouping

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

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

即:以三个为一组连接元素。

谢谢:D

3 个答案:

答案 0 :(得分:3)

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

list1 to 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相似(基准测试未显示)。

this post

中使用@JoshOBrien的想法更进一步
# 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 to 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

答案 1 :(得分:2)

这是另一个版本,它比@ Arun的两种方法都快(imo以牺牲可读性为代价,与他的方法1相比,遗憾的是它比他的方法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

答案 2 :(得分:2)

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的倍数的变体以及不同的解决方案。