如何从单个项目列表中删除未命名元素?

6

这可能听起来像一个非常初学者的问题,事实上它也可能是一个非常基础和愚蠢的问题,但是我在做它时却感到头痛。

假设我有一个单项列表

v <- as.list("1, 2, 3,")

v
[[1]]
[1] "1, 2, 3,"

现在,我想将所有的项目拆分成单独的项目。

v2 <- lapply(str_split(v, pattern = ","), trimws)
v2
[[1]]
[1] "1" "2" "3" "" 

现在我想从这个列表的第一个且唯一的项目中删除"",但不使用[]怎么办?

据我理解(可能会有错误),当我知道列表中元素的数量/位置时,使用 []。但在这种情况下,我并不真正了解它的位置? - AnilGoyal
你仍然可以使用动态元素向量的[]来删除 - 请参见下面的解决方案。 - deschen
你为什么要使用单个项目的“列表”而不是字符向量? - A5C1D2H2I1M1N2O1R2T1
@A5C1D2H2I1M1N2O1R2T1,感谢您的询问和关注。在使用列表方面,我并没有特别的原因,只是想通过使用R的“列表”方法来学习,在不总是使用“向量”的情况下进行学习。我觉得只有充分利用列表,才能发挥R的全部潜力。请看看我的其他问题,我仍在努力解决。在过去的几个月中,我发现SO是自学的最佳途径。 - AnilGoyal
1
@AnilGoyal,同意- SO 是自学的好方式。提出问题的部分原因是为了更好地了解所探索问题的范围(例如,为什么要在不使用 [] 的情况下解决此问题,以及为什么您会从单项列表开始)。例如,我认为理解 jay.sf 的 strsplit 为什么有效是他回答中的重要教训(并且在 ?strsplit 中有记录)。 - A5C1D2H2I1M1N2O1R2T1
6个回答

6

使用nzchar函数.

lapply(v2, function(x) x[nzchar(x)])
# [[1]]
# [1] "1" "2" "3"

或者一开始就使用base::strsplit,它似乎更为高级。

lapply(strsplit(v[[1]], ","), trimws)
# [[1]]
# [1] "1" "2" "3"

1
为什么要使用x[nchar(x) > 0]而不是更快的x[nzchar(x)] - A5C1D2H2I1M1N2O1R2T1
1
@A5C1D2H2I1M1N2O1R2T1 你说得完全正确,非常感谢更新。 - jay.sf

3
你可以使用ncharFilter
v2 <- lapply(str_split(v, pattern = ",\\s?"), Filter, f = nchar)

这提供了

> v2
[[1]]
[1] "1" "2" "3"

2
还可以使用 setdiff 选项来移除 ""
lapply(str_split(v, pattern = ",\\s*"), setdiff, "")
#[[1]]
#[1] "1" "2" "3"

2

无论你有一个或多个项目的列表,我可能会这样做:

无论您的列表只有一个项目还是多个项目,我都会进行类似的操作:
str_split(gsub("^,|,$|\\s+", "", v), ",")

或者更好的方法是:
strsplit(gsub("^,|,$|\\s+", "", v), ",", TRUE)
# [[1]]
# [1] "1" "2" "3"

(或者,根据您实际的数据,甚至可以使用strsplit(gsub("^,|,$|\\s", "", gsub(", ,", ",", v, fixed = TRUE)), ",", TRUE)。)


以下是一个示例,其中包含多个元素的list,而不是只有一个元素的list

v <- rep(v, 2500)

我已经将其他答案放入函数中,并根据需要进行修改,使它们适用于多个list元素。以下是我测试过的函数:

fun_a5a <- function() str_split(gsub("^,|,$|\\s+", "", v), ",")
fun_a5b <- function() strsplit(gsub("^,|,$|\\s+", "", v), ",", TRUE)

fun_ak <- function() lapply(str_split(v, pattern = ",\\s*"), setdiff, "")

fun_des <- function() {
  v2 <- lapply(str_split(v, pattern = ","), trimws)
  lapply(v2, function(x) x[x != ""])
}

fun_hfa <- function() Map(function(x){trimws(unlist(strsplit(x, ",")))}, v)
fun_hfb <- function() sapply(v, strsplit, ",\\s*")

fun_jay <- function() lapply(unlist(lapply(v, strsplit, ","), recursive = FALSE), trimws)

fun_tica <- function() lapply(str_split(v, pattern = ",\\s?"), Filter, f = nchar)
fun_ticb <- function() lapply(str_split(v, pattern = ",\\s?"), Filter, f = nzchar)

以下是结果:
bench::mark(fun_a5a(), fun_a5b(), 
            fun_ak(), 
            fun_des(), 
            fun_hfa(), fun_hfb(), 
            fun_jay(),
            fun_tica(), fun_ticb())
# # A tibble: 9 x 13
#   expression     min  median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result
#   <bch:expr> <bch:t> <bch:t>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>
# 1 fun_a5a()   2.47ms  2.63ms     372.     58.7KB     2.04   183     1    491.4ms <list…
# 2 fun_a5b()   1.85ms   1.9ms     517.     58.7KB     2.03   255     1    493.4ms <list…
# 3 fun_ak()   14.17ms 14.85ms      66.8    58.7KB    44.5     15    10    224.5ms <list…
# 4 fun_des()  62.86ms 62.86ms      15.9    78.3KB   111.       1     7     62.9ms <list…
# 5 fun_hfa()  82.17ms 82.17ms      12.2    19.6KB    73.0      1     6     82.2ms <list…
# 6 fun_hfb()  13.36ms 13.59ms      72.9    90.8KB     9.11    32     4    438.9ms <list…
# 7 fun_jay()   71.3ms  71.3ms      14.0    58.7KB    84.2      1     6     71.3ms <list…
# 8 fun_tica() 21.97ms  22.2ms      44.5    58.7KB    66.8      8    12    179.7ms <list…
# 9 fun_ticb() 13.12ms 13.59ms      73.5    58.7KB    44.1     20    12    272.2ms <list…
# # … with 3 more variables: memory <list>, time <list>, gc <list>

ggplot::autoplot(.Last.value)

enter image description here


1

更丑陋的版本(仅作为额外的想法,但jay.sf的解决方案似乎更可取):

基于您的v2输入:

delete <- which(v2[[1]] == "")

v2[[1]] <- v2[[1]][-delete]

# [[1]]
# [1] "1" "2" "3"

我会使用 nzchar。另外,由于您已经创建了一个逻辑向量,可以使用该向量进行子集化,所以您不需要使用 which 计算索引。 - A5C1D2H2I1M1N2O1R2T1

1
使用Map()
Map(function(x){trimws(unlist(strsplit(x, ",")))}, v)

使用`sapply()`函数:
sapply(v, strsplit, ",\\s*")

1
有趣!已点赞。请解释正则表达式",|, "在这里的目的。 - AnilGoyal
1
@AnilGoyal 应该在 ", " 上进行拆分而不是 ",",这可以避免调用 trimws() 函数。 - hello_friend

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