使用grep访问列表元素

时间:2017-04-07 09:04:24

标签: r list indexing grep lapply

如何使用grep输出直接访问列表项? 到目前为止,我发现了一种间接的方法,它涉及列表和grep输出的不列名:

list1 <- list(c("Group1", "Group2", "Group3"))
list2 <- list(c("GroupA", "GroupB", "GroupC"))
list.all <- c(list1,list2)               

以下代码有效,但我正在寻找unlist()

的替代方案
idx <- unlist(lapply(list.all, function(x) grepl("Group1", x)))
unlist(list.all)[idx]

返回&#34; Group1&#34;如预期的那样。

我正在寻找语法方面 - 但不起作用 - 是通过以下方式直接访问列表元素:

list.all[[id.index]]

但这显然会返回&gt;无效的下标类型&#39; list&#39;

任何想法都将不胜感激!

2 个答案:

答案 0 :(得分:1)

好的,所以我已经做了一些思考。不幸的是,我没有简单的事情(就像您要求的那样),但是我以几种不同的方式切分了这一点,并认为分享是一件好事。当然,如果您想简单起见,可以将其中任何一个转换为函数。

此外,出于价值所在,我这样做是为了告诉自己如何使用列表中的匹配文本,这就是为什么它倾向于成为顶部(也许)的小矮人的原因。

数据

list1 <- list(c("Group1", "Group2", "Group3"))
list2 <- list(c("GroupA", "GroupB", "GroupC"))

list3 <- list(rep(paste0("Group", 1:1e5), 2))
list4 <- list(rep(paste0("Group", LETTERS), ceiling(2e5 / 26)))

list.12 <- c(list1,list2)
list.34 <- c(list3,list4)

返回向量的选项

选项1 (您的选项):

idx <- unlist(lapply(list.12, function(x) grepl("Group1", x, fixed = T)))
unlist(list.12)[idx]
[1] "Group1"

选项2

idx.list <- lapply(list.12, grepl, pattern = "Group1", fixed = TRUE)
match.list <- Map(`[`, list.12, idx.list)
unlist(match.list)
[1] "Group1"

选项3

unlist(list.12)[(grep("Group1", unlist(list.12), fixed = TRUE))]
[1] "Group1"

选项4

unlist(list.12)[(stri_detect_fixed(unlist(list.12), "Group1"))]
[1] "Group1"

以及小清单的基准测试

Unit: microseconds
  expr    min     lq     mean  median     uq      max neval
 opt_1  7.001  8.305 153.6345  8.7790  9.668 1454.531    10
 opt_2 12.234 12.433  14.6120 13.0425 14.481   26.645    10
 opt_3  3.744  3.861   5.7395  4.0010  5.509   18.314    10
 opt_4  4.511  4.763   7.1403  5.1635  6.047   18.205    10

输出 list.34 上述所有选项

[1] "Group1"    "Group10"   "Group11"   "Group12"   "Group13"   "Group14"  
[7] "Group15"   "Group16"   "Group17"   "Group18"   "Group19"   "Group100" 
[13] "Group101"  "Group102"  "Group103"  "Group104"  "Group105"  "Group106" 
[19] "Group107"  "Group108"  "Group109"  "Group110"  "Group111"  "Group112"
...........
[997] "Group1885" "Group1886" "Group1887" "Group1888"
[ reached getOption("max.print") -- omitted 21224 entries ]

和基准(对于它们的价值):

Unit: milliseconds
  expr      min       lq     mean   median       uq      max neval
 opt_1 20.28270 21.59880 24.63574 22.97677 25.07883 34.28110    10
 opt_2 15.65542 17.01358 19.29739 17.47097 18.95579 28.15225    10
 opt_3 21.87411 23.17457 25.59646 24.06683 25.01356 40.57871    10
 opt_4 31.78084 34.60584 38.84164 38.00180 42.79115 50.28889    10

因此,看起来选项2在使用较大数据时可以最佳缩放。但是输出说明了为什么在使用grepgrepl或其他使用正则表达式的函数时必须格外小心。

返回矢量的“更安全”选项

因此,我认为包括一些“更安全”的选择可能会有所帮助。而且,更安全地说,我的意思是它们将只与文本“ Group1”匹配。他们也不会匹配“ Group11 ...”

安全选项1

unlist(list.12)[match(unlist(list.12), "Group1", nomatch = F)]
[1] "Group1"

安全选项2

unlist(list.12)[unlist(list.12) %in% "Group1"]
[1] "Group1"

安全选项3

idx.list <- lapply(list.12, grepl, pattern = "\\bGroup1\\b")
match.list <- Map(`[`, list.12, idx.list)
unlist(match.list)
[1] "Group1"

“更安全”或“完全匹配”选项的基准:

Unit: microseconds
   expr    min     lq    mean  median     uq    max neval
 safe_1  3.063  3.124  3.9562  3.7135  4.172  7.157    10
 safe_2  2.897  3.089  5.8281  3.3700  4.436 26.729    10
 safe_3 27.978 28.564 34.1458 28.9110 30.869 75.457    10

输出list.34 输出矢量的所有更安全的选项

[1] "Group1" "Group1"

预期此输出是因为"Group1"中只有两个list.34

list.34的基准以获得更安全的选项。

Unit: milliseconds
   expr       min        lq      mean    median        uq       max neval
 safe_1  13.79823  14.45908  17.40700  15.07796  23.18696  23.95939    10
 safe_2  15.61516  17.61696  21.76075  21.15972  25.17552  28.91110    10
 safe_3 120.27222 125.82341 129.01684 129.11074 131.15969 141.02159    10

返回列表的选项

最后,我认为将比赛保持在列表形式可能也很有用。因此,我采用了几种方法,并对它们进行了基准测试。请注意,选项1和4返回相同的结果,选项2和3返回近似值。相同的结果。

列出选项1

idx.list <- lapply(list.12, grepl, pattern = "\\bGroup1\\b", fixed = F)
match.list <- Map(`[`, list.12, idx.list)
match.list[lapply(match.list, length) > 0]
[[1]]
[1] "Group1"

仅返回匹配的元素

列出选项2

Filter(function(x) "Group1" %in% x, list.12)
[[1]]
[1] "Group1" "Group2" "Group3"

返回包含匹配元素的向量

列出选项3

list.12[which(unlist(list.12) %in% "Group1")]
[[1]]
[1] "Group1" "Group2" "Group3"

还返回包含匹配元素的向量

列表选项4

list4_ind <- Map(`%in%`, list.12[which(unlist(list.12) %in% "Group1")], "Group1")
Map(`[`, list.12[which(unlist(list.12) %in% "Group1")], list4_ind)
[[1]]
[1] "Group1"

类似于选项1,它仅返回匹配的元素

列表选项的基准

Unit: microseconds
       expr    min     lq     mean  median     uq      max neval
 list_opt_1 37.837 38.943  48.4543 46.3615 48.831   85.498    10
 list_opt_2  8.474  9.749 243.2209 11.2840 12.538 2330.869    10
 list_opt_3  3.384  3.876   4.9735  4.2705  5.051   11.233    10
 list_opt_4 22.056 22.209  27.1948 25.8670 29.827   36.355    10

list的输出。34输出列表的所有选项:

选项1和4

[[1]]
[1] "Group1" "Group1"

选项2和3 (实际上,选项2不会将空的第二个元素返回到列表,仅返回list1):

[[1]]
   [1] "Group1"    "Group2"    "Group3"    "Group4"    "Group5"    "Group6"   
   [7] "Group7"    "Group8"    "Group9"    "Group10"   "Group11"   "Group12"  
  [13] "Group13"   "Group14"   "Group15"   "Group16"   "Group17"   "Group18"
  ..........
  [985] "Group985"  "Group986"  "Group987"  "Group988"  "Group989"  "Group990" 
  [991] "Group991"  "Group992"  "Group993"  "Group994"  "Group995"  "Group996" 
  [997] "Group997"  "Group998"  "Group999"  "Group1000"
  [ reached getOption("max.print") -- omitted 199000 entries ]

[[2]]
NULL

再次,返回包含匹配项的整个向量。

和基准:

Unit: milliseconds
       expr        min         lq       mean     median         uq        max neval
 list_opt_1 120.899425 121.931426 128.245115 130.018640 131.247377 136.823413    10
 list_opt_2   1.365003   2.398965   3.554334   2.499366   2.560078   9.524567    10
 list_opt_3  11.169013  11.987195  16.755645  15.267181  21.299495  24.538944    10
 list_opt_4  27.388212  32.125164  40.104322  40.680335  47.248335  48.679709    10

摘要:

  • 如果要返回不带正则表达式的精确(安全)模式的向量,则安全选项1似乎可以最佳缩放。

  • 如果要使用正则表达式返回向量,则安全选项3最好缩放以获取更多数据。它与常规选项2相同。

  • 如果要只返回匹配项的列表,请使用列表选项4。

  • 如果要使用正则表达式仅包含匹配项的列表,请使用列表选项1。

  • 如果要返回包含列表内 的向量,列表选项2中的Filter非常快。

答案 1 :(得分:0)

受到@Andrew精心解答的启发,我发现了最简单的方法来考虑他对安全方法的考虑,同时又保持了最大的可读性。主要学分归@Andrew所有。我的答案仅适用于那些不想阅读他有趣的分析的人。这是我的建议:

idx <- unlist(list.all) %in% "Group1"
unlist(list.all)[idx]

"Group1" "Group1" "Group1"

或更短或更精致的dpyr:

unlist(list.all) %in% "Group1" %>% unlist(list.all)[.]

我知道这仍然不能摆脱unlist()-我的最初目标-但可以避免由于grepls的部分匹配而导致获得错误结果的风险。