在R中使用lapply处理列表的子集,并返回与原始列表长度相同的列表

4
我希望使用lapply对列表元素的子集(即字符字符串)应用正则表达式操作,并返回与原始列表长度相同的列表。 列表元素是长字符串(从读取长文本文件并将段落折叠成单个字符串中派生而来)。 正则表达式操作仅适用于列表元素/字符串的子集。 我希望未经子集处理的列表元素(字符字符串)以其原始状态返回。
正则表达式操作是来自stringr包的str_extract,即我想从较长的字符串中提取子字符串。 我基于文件名中的正则表达式模式对列表元素进行子集处理。
以下是一个简化数据的示例:
library(stringr)
texts <- as.list(c("abcdefghijkl", "mnopqrstuvwxyz", "ghijklmnopqrs", "uvwxyzabcdef"))
filenames <- c("AB1997R.txt", "BG2000S.txt", "MN1999R.txt", "DC1997S.txt")
names(texts) <- filenames
regexp <- "abcdef"

我提前知道我想要对哪些字符串应用正则表达式操作,因此我想要对这些字符串进行子集处理。也就是说,我不想对列表中的所有元素运行正则表达式,因为这样做会返回一些无效结果(在这个简化的示例中并不明显)。
我已经尝试了一些天真的努力,例如:
x <- lapply(texts[str_detect(names(texts), "1997")], str_extract, regexp)
> x
$AB1997R.txt
[1] "abcdef"

$DC1997S.txt
[1] "abcdef"

该函数返回一个缩短长度的列表,只包含找到的子字符串。但我想要得到的结果是:

> x
$AB1997R.txt
[1] "abcdef"

$BG2000S.txt
[1] "mnopqrstuvwxyz"

$MN1999R.txt
[1] "ghijklmnopqrs"

$DC1997S.txt
[1] "abcdef"

不包含正则表达式模式的字符串将以原始状态返回。

我已经了解了stringrlapplyllply(在plyr包中),但是许多操作使用数据框作为示例,而不是列表,并且不涉及字符串的正则表达式操作。我可以使用for循环实现我的目标,但是我正在试图摆脱这种方式,并更好地使用apply类函数,因为通常会建议这样做。

2个回答

4
你可以使用子集操作符[<-
x <- texts
is1997 <- str_detect(names(texts), "1997")
x[is1997] <- lapply(texts[is1997], str_extract, regexp)
x
# $AB1997R.txt
# [1] "abcdef"
#
# $BG2000S.txt
# [1] "mnopqrstuvwxyz"
#
# $MN1999R.txt
# [1] "ghijklmnopqrs"
#
# $DC1997S.txt
# [1] "abcdef"
#

非常感谢。我曾尝试在左侧和右侧进行子集操作,但最初没有正确地执行,然后认为解决方案一定很复杂。这是理想的解决方案。 - Brigitte
1
我做错的是尝试使用双括号进行子集操作。对于其他新手来说,我发现双括号返回与元素原始类相同的对象,而单括号返回列表对象。 - Brigitte

3
你可以尝试使用 sub
  sub(paste0('.*(', regexp, ').*'), '\\1', texts)
  # AB1997R.txt      BG2000S.txt      MN1999R.txt      DC1997S.txt 
  #  "abcdef" "mnopqrstuvwxyz"  "ghijklmnopqrs"         "abcdef" 

此外,如果您需要将“texts”名称与1997匹配,我们可以使用grep
  indx <- grep('1997', names(texts))
  texts[indx] <- sub(paste0('.*(', regexp, ').*'), '\\1', texts[indx])
  as.list(texts)

非常感谢这个。我尽可能地试着坚持使用stringr。另外,由于文本非常长,以 .* 开头的模式需要很长时间才能到达正则表达式匹配,可能是由于回溯造成的。所以我选择了str_extract而不是str_replace。 - Brigitte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接