1

我有一个特定的清单:

lst <- list(A=c('aa', 'bb', 'cc'), B=c('ee', 'ff' ,'gg') ,C=c('aa', 'bb', 'bbc', 'dd'))

$A
[1] "aa" "bb" "cc"

$B
[1] "ee" "ff" "gg"

$C
[1] "aa"  "bb"  "bbc" "dd" 

str_extract_all用来收集符合特定模式的部分数据。

> data <- str_extract_all(lst, 'bb') %>% unlist() %>% compact()

[1] "bb" "bb" "bb"

我想在一个小标题上显示结果,指示从中提取模式的源(即列表标题)。由于在 $C 中重复出现“bb”,这会产生以下错误。

> tibble(data = data, src = names(lst[grep('bb', lst)]))
錯誤: Column `src` must be length 1 or 3, not 2

当没有重复出现时,代码可以正常工作。

> lst <- list(A=c('aa', 'bb', 'cc'), B=c('ee', 'ff', 'gg') ,C=c('aa', 'bb', 'cc', 'dd'))

$A
[1] "aa" "bb" "cc"

$B
[1] "ee" "ff" "gg"

$C
[1] "aa" "bb" "cc" "dd"

> data <- str_extract_all(lst, 'bb') %>% unlist() %>% compact()
> tibble(data = data, src = names(lst[grep('bb', lst)]))
# A tibble: 2 x 2
   data   src
  <chr> <chr>
1    bb     A
2    bb     C

如何编码以避免错误?

# A tibble: 2 x 2
   data   src
  <chr> <chr>
1    bb     A
2    bb     C
3    bbc    C

在研究我的解决方案时,我认为我的问题最终归结为:

> pattern <- c('bb', 'ee')
> grep(paste(pattern, collapse="|"), lst)
[1] 1 2 3

grep()告诉我具体的字符串模式可以在我列表的第一项和第三项中找到。

我宁愿做的是在grep()发现模式重复出现时重复项目编号。

[1] 1 2 3 3

我应该能够使用这种模式来生成一个源向量,并在以后cbind()使用我的str_extract()结果:

> rslt <- tibble(data = c('bb', 'ee', 'bb', 'bbc'), src = c( 'A', 'B', 'C', 'C'))

# A tibble: 4 x 2
   data   src
  <chr> <chr>
1    bb     A
2    ee     B
3    bb     C
4   bbc     C

解决方案:

这是我自己解决问题的方法。

lst <- list(A=paste0('aa', str_dup("xy", 50), "bb", str_dup("ov", 50), "bb", str_dup("nm", 50), 'cc'), B=paste0('ee', 'ff' ,'gg') ,C=paste0('aa', str_dup("qed", 50), "bb", str_dup("sh", 50), 'bbc', 'dd'))

x <- str_count(lst, "bb") #Count instances to indicate repeats
x <- x[x != 0] #Remove the 0s
src.id <- mapply(rep, grep('bb', lst), x) %>% unlist() #Repeat source index to generate source vector
rslt <- tibble(str = str_extract_all(lst, "..bb..") %>% unlist() %>% compact(), src = names(lst[src.id]))

# A tibble: 4 x 2
     str   src
   <chr> <chr>
1 xybbov     A
2 ovbbnm     A
3 edbbsh     C
4 shbbcd     C

即使重复的模式嵌入到子字符串中(如上),这也有效。

4

3 回答 3

1

这变得有点混乱,但以下工作:

library(data.table)
rbindlist(lapply(lst, function(x) data.table(mtch = grep('bb', x, value = TRUE))),
          idcol = 'where')
#    where mtch
# 1:     A   bb
# 2:     C   bb
# 3:     C  bbc
于 2017-10-04T06:58:34.107 回答
1

这里有一个tidyverse想法,

library(tidyverse)

unlist(lst) %>% 
    data.frame() %>% 
    rename('v1' = '.') %>% 
    rownames_to_column('v2') %>% 
    filter(grepl('bb', v1)) %>% 
    mutate(v2 = sub('\\d+', '', v2))

这使,

  v2  v1
1  A  bb
2  C  bb
3  C bbc
于 2017-10-04T07:12:17.217 回答
1

这是在基础 R 中执行此操作的一种方法。

# get the matching values for each list element
tmp <- lapply(lst, function(x) x[grep("bb", x)])

# build a data.frame
data.frame(val=unlist(tmp, use.names=FALSE), src=rep(names(tmp), lengths(tmp)))

unlist从所选项目返回一个向量,并且 use.names=FALSE 允许data.frame返回标准行名称,而不是由. 生成的名称unlist。的第二个参数data.frame重复 tmp 中元素的名称以匹配匹配的元素。

这返回

  val src
1  bb   A
2  bb   C
3 bbc   C

对于较长的字符串,您只想匹配两边周围的 3 个字符,您可以像这样x[grep(...)]替换regmatches(regexpr)

tmp <- lapply(lst, function(x) regmatches(x, regexpr("(...)?bb(...)?", x)))
# unchanged from above
data.frame(val=unlist(tmp, use.names=FALSE), src=rep(names(tmp), lengths(tmp)))

对于第二个示例,这将返回

       val src
1 yxybbxyx   A
2 qedbbxyx   C
3       bb   C
于 2017-10-04T12:19:13.613 回答