从列表中重复出现的字符串模式实例中提取 header 数据

Extract header data from instances of string pattern in list, where there are repeated occurrences

我有一个列表:

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"

我想在小标题上显示结果,指示从中提取模式的来源(即列表 header)。由于在 $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

即使在 sub-string 中嵌入重复模式(如上),此方法也有效。

这变成了一个小问题,但以下工作:

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

这是一个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

这是在 base 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 returns 是所选项目的向量,use.names=FALSE 允许 data.frame 到 return 标准行名称而不是名称将由 unlist 生成。 data.frame 的第二个参数重复 tmp 中元素的名称以匹配匹配的元素。

这个returns

  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)))

对于第二个例子,这个returns

       val src
1 yxybbxyx   A
2 qedbbxyx   C
3       bb   C