【问题标题】:How can I remove an element from a list?如何从列表中删除元素?
【发布时间】:2010-10-13 17:18:21
【问题描述】:

我有一个列表,我想从中删除一个元素。我该怎么做?

我已经尝试在参考手册中查找我认为该函数的明显名称,但我没有找到任何合适的名称。

【问题讨论】:

  • 取决于您是否要按值删除它,例如“值 5”,或按索引/索引“索引 5 处的元素”或“索引 c(5:6,10)?如果您想按值删除并且有重复项,那么您只想删除重复项,第一次或最后一次出现,还是全部?是否保证列表包含您的元素/索引?我们是否需要处理列表为空的情况?我们是否需要确保 NA 通过(/排除)?是列表保证是平的还是可以嵌套的?以后有多少深?
  • setdiff(myList,elementToRemove)

标签: r list indexing r-faq


【解决方案1】:

purrr 包中有几个选项没有被提及:

pluckassign_in 可以很好地处理嵌套值,您可以使用名称和/或索引的组合来访问它:

library(purrr)

l <- list("a" = 1:2, "b" = 3:4, "d" = list("e" = 5:6, "f" = 7:8))

# select values (by name and/or index)
all.equal(pluck(l, "d", "e"), pluck(l, 3, "e"), pluck(l, 3, 1))
[1] TRUE

# or if element location stored in a vector use !!!
pluck(l, !!! as.list(c("d", "e")))
[1] 5 6

# remove values (modifies in place)
pluck(l, "d", "e") <- NULL

# assign_in to remove values with name and/or index (does not modify in place)
assign_in(l, list("d", 1), NULL)
$a
[1] 1 2

$b
[1] 3 4

$d
$d$f
[1] 7 8

或者您可以通过分配zap()NULL 来使用modify_list 删除值:

all.equal(list_modify(l, a = zap()), list_modify(l, a = NULL))
[1] TRUE

您可以使用带有discardkeep 的谓词函数删除或保留元素:

# remove numeric elements
discard(l, is.numeric)
$d
$d$e
[1] 5 6

$d$f
[1] 7 8

# keep numeric elements
keep(l, is.numeric)
$a
[1] 1 2

$b
[1] 3 4

【讨论】:

    【解决方案2】:

    这是一个可以使用基数 R 完成的简单解决方案。它从原始数字列表中删除数字 5。您可以使用相同的方法从列表中删除您想要的任何元素。

    #the original list
    original_list = c(1:10)
    
    #the list element to remove
    remove = 5
    
    #the new list (which will not contain whatever the `remove` variable equals)
    new_list = c()
    
    #go through all the elements in the list and add them to the new list if they don't equal the `remove` variable
    counter = 1
    for (n in original_list){
      if (n != ){
        new_list[[counter]] = n
        counter = counter + 1
      }
    }
    

    new_list 变量不再包含 5。

    new_list
    # [1]  1  2  3  4  6  7  8  9 10
    

    【讨论】:

      【解决方案3】:

      您还可以使用magrittr 包的extract 函数从列表中进行负索引以删除列表项。

      a <- seq(1,5)
      b <- seq(2,6)
      c <- seq(3,7)
      l <- list(a,b,c)
      
      library(magrittr)
      
      extract(l,-1) #simple one-function method
      [[1]]
      [1] 2 3 4 5 6
      
      [[2]]
      [1] 3 4 5 6 7
      

      【讨论】:

        【解决方案4】:

        如果您想避免使用数字索引,可以使用

        a <- setdiff(names(a),c("name1", ..., "namen"))
        

        从 a 中删除名称 namea...namen。这适用于列表

        > l <- list(a=1,b=2)
        > l[setdiff(names(l),"a")]
        $b
        [1] 2
        

        以及向量

        > v <- c(a=1,b=2)
        > v[setdiff(names(v),"a")]
        b 
        2
        

        【讨论】:

          【解决方案5】:

          -(负号)与元素的位置一起使用,例如,如果要删除第三个元素,则将其用作your_list[-3]

          输入

          my_list <- list(a = 3, b = 3, c = 4, d = "Hello", e = NA)
          my_list
          # $`a`
          # [1] 3
          
          # $b
          # [1] 3
          
          # $c
          # [1] 4
          
          # $d
          # [1] "Hello"
          
          # $e
          # [1] NA
          

          从列表中删除单个元素

           my_list[-3]
           # $`a`
           # [1] 3
          
           # $b
           # [1] 3
          
           # $d
           # [1] "Hello"
          
           # $e
           [1] NA
          

          从列表中删除多个元素

           my_list[c(-1,-3,-2)]
           # $`d`
           # [1] "Hello"
          
           # $e
           # [1] NA
          

           my_list[c(-3:-5)]
           # $`a`
           # [1] 3
          
           # $b
           # [1] 3
          

           my_list[-seq(1:2)]
           # $`c`
           # [1] 4
          
           # $d
           # [1] "Hello"
          
           # $e
           # [1] NA
          

          【讨论】:

            【解决方案6】:

            我想补充一点,如果它是一个命名列表,您可以简单地使用within

            l <- list(a = 1, b = 2)    
            > within(l, rm(a))
            $b
            [1] 2
            

            这样你就可以覆盖原来的列表了

            l <- within(l, rm(a)) 
            

            从列表l 中删除名为a 的元素。

            【讨论】:

            • 做多个within(l, rm(a, b))
            • 从一个字符向量做多个:x &lt;- c("a","b"); within(l,rm(list=x))
            【解决方案7】:

            对于命名列表,我发现这些辅助函数很有用

            member <- function(list,names){
                ## return the elements of the list with the input names
                member..names <- names(list)
                index <- which(member..names %in% names)
                list[index]    
            }
            
            
            exclude <- function(list,names){
                 ## return the elements of the list not belonging to names
                 member..names <- names(list)
                 index <- which(!(member..names %in% names))
                list[index]    
            }  
            aa <- structure(list(a = 1:10, b = 4:5, fruits = c("apple", "orange"
            )), .Names = c("a", "b", "fruits"))
            
            > aa
            ## $a
            ##  [1]  1  2  3  4  5  6  7  8  9 10
            
            ## $b
            ## [1] 4 5
            
            ## $fruits
            ## [1] "apple"  "orange"
            
            
            > member(aa,"fruits")
            ## $fruits
            ## [1] "apple"  "orange"
            
            
            > exclude(aa,"fruits")
            ## $a
            ##  [1]  1  2  3  4  5  6  7  8  9 10
            
            ## $b
            ## [1] 4 5
            

            【讨论】:

              【解决方案8】:

              不知道你是否还需要这个问题的答案,但我从我有限的(3 周的自学 R)经验中发现,使用 NULL 分配实际上是错误的或次优的,尤其是如果您正在以类似 for 循环的方式动态更新列表。

              更准确地说,使用

              myList[[5]] <- NULL
              

              会抛出错误

              myList[[5]]

              提供的元素多于替换的元素

              我发现工作更一致的是

              myList <- myList[[-5]]
              

              【讨论】:

              • 好答案!但是,我认为 [[-5]] 应该是单方括号,否则您只会取消选择该列表元素的内容,而不是元素本身。好吧,至少使用双方括号会给我这个错误:“尝试选择多个元素”。当时对我有用的是:myList &lt;- myList[-5].
              【解决方案9】:

              使用 lapply 和 grep:

              lst <- list(a = 1:4, b = 4:8, c = 8:10)
              # say you want to remove a and c
              toremove<-c("a","c")
              lstnew<-lst[-unlist(lapply(toremove, function(x) grep(x, names(lst)) ) ) ]
              #or
              pattern<-"a|c"
              lstnew<-lst[-grep(pattern, names(lst))]
              

              【讨论】:

                【解决方案10】:

                只是想快速添加(因为我在任何答案中都没有看到),对于命名列表,您也可以使用l["name"] &lt;- NULL。例如:

                l <- list(a = 1, b = 2, cc = 3)
                l['b'] <- NULL
                

                【讨论】:

                  【解决方案11】:

                  您可以使用which

                  x<-c(1:5)
                  x
                  #[1] 1 2 3 4 5
                  x<-x[-which(x==4)]
                  x
                  #[1] 1 2 3 5
                  

                  【讨论】:

                    【解决方案12】:

                    这个怎么样?同样,使用索引

                    > m <- c(1:5)
                    > m
                    [1] 1 2 3 4 5
                    
                    > m[1:length(m)-1]
                    [1] 1 2 3 4
                    

                    > m[-(length(m))]
                    [1] 1 2 3 4
                    

                    【讨论】:

                    • m 是向量,不是列表
                    • 该方法确实适用于列表,但 OP 很幸运,可能需要更多括号:m[1:(length(m) - 1)]
                    【解决方案13】:

                    有 rlist 包 (http://cran.r-project.org/web/packages/rlist/index.html) 来处理各种列表操作。

                    示例 (http://cran.r-project.org/web/packages/rlist/vignettes/Filtering.html):

                    library(rlist)
                    devs <- 
                      list(
                        p1=list(name="Ken",age=24,
                          interest=c("reading","music","movies"),
                          lang=list(r=2,csharp=4,python=3)),
                        p2=list(name="James",age=25,
                          interest=c("sports","music"),
                          lang=list(r=3,java=2,cpp=5)),
                        p3=list(name="Penny",age=24,
                          interest=c("movies","reading"),
                          lang=list(r=1,cpp=4,python=2)))
                    
                    list.remove(devs, c("p1","p2"))
                    

                    结果:

                    # $p3
                    # $p3$name
                    # [1] "Penny"
                    # 
                    # $p3$age
                    # [1] 24
                    # 
                    # $p3$interest
                    # [1] "movies"  "reading"
                    # 
                    # $p3$lang
                    # $p3$lang$r
                    # [1] 1
                    # 
                    # $p3$lang$cpp
                    # [1] 4
                    # 
                    # $p3$lang$python
                    # [1] 2
                    

                    【讨论】:

                    • 如何删除本示例中的 python 或 lang 项?
                    【解决方案14】:

                    如果您有一个命名列表并想删除特定元素,您可以尝试:

                    lst <- list(a = 1:4, b = 4:8, c = 8:10)
                    
                    if("b" %in% names(lst)) lst <- lst[ - which(names(lst) == "b")]
                    

                    这将创建一个列表lst,其中包含元素abc。第二行在检查元素b 是否存在后删除它(以避免@hjv 提到的问题)。

                    或更好:

                    lst$b <- NULL
                    

                    这样尝试删除不存在的元素(例如lst$g &lt;- NULL)不会有问题

                    【讨论】:

                      【解决方案15】:

                      从单行列表中删除 Null 元素:

                      x=x[-(which(sapply(x,is.null),arr.ind=TRUE))]

                      干杯

                      【讨论】:

                      • x 是一个空列表时,此代码会中断。使用 plyr 中的 compact 代替此任务。
                      • 此外,如果列表中没有空值,-(which(sapply(x,is.null),arr.ind=TRUE)) 将返回 named integer(0),这将完全删除该行。
                      【解决方案16】:

                      以下是如何在 R 中删除 list 的最后一个元素:

                      x <- list("a", "b", "c", "d", "e")
                      x[length(x)] <- NULL
                      

                      如果 x 可能是一个向量,那么您需要创建一个新对象:

                      x <- c("a", "b", "c", "d", "e")
                      x <- x[-length(x)]
                      
                      • 适用于列表向量

                      【讨论】:

                      • @krlmlr:相反,这个解决方案比 Florian 的回答更通用,因为它在集合类型上是多态的。
                      • @DanBarowy:我错了:这似乎是乍得的答案(已接受的答案)和弗洛里安的综合......不过,这是一个很好的简短总结。
                      【解决方案17】:

                      如果您不想就地修改列表(例如,将删除了元素的列表传递给函数),您可以使用索引:负索引表示“不包含此元素”。

                      x <- list("a", "b", "c", "d", "e"); # example list
                      
                      x[-2];       # without 2nd element
                      
                      x[-c(2, 3)]; # without 2nd and 3rd
                      

                      此外,逻辑索引向量也很有用:

                      x[x != "b"]; # without elements that are "b"
                      

                      这也适用于数据框:

                      df <- data.frame(number = 1:5, name = letters[1:5])
                      
                      df[df$name != "b", ];     # rows without "b"
                      
                      df[df$number %% 2 == 1, ] # rows with odd numbers only
                      

                      【讨论】:

                      • 只有在列表元素中有单个项目“b”时,您的逻辑索引才有效。你不能以这种方式删除,比如x$b,也不能从列表元素x[[2]] = c("b","k") 中删除“b”。
                      • 关于单个与多个项目:您可以使用%in% 对多个项目进行测试。我不确定您所说的“无法删除 x$b”是什么意思——您的意思是删除整个列 b
                      【解决方案18】:

                      我根本不知道 R,但是通过一些创造性的谷歌搜索让我来到这里:http://tolstoy.newcastle.edu.au/R/help/05/04/1919.html

                      那里的关键引述:

                      我没有找到关于如何从列表中删除元素的 R 的明确文档,但反复试验告诉我

                      我的列表[[5]]

                      将删除第 5 个元素,然后“关闭”由删除该元素引起的孔。这会影响索引值,所以我必须小心删除元素。我必须从列表的后面工作到前面。

                      response to that post later in the thread 声明:

                      要删除列表中的元素,请参阅 R FAQ 7.1

                      relevant section of the R FAQ 说:

                      ... 不要将 x[i] 或 x[[i]] 设置为 NULL,因为这会从列表中删除相应的组件。

                      这似乎告诉您(以某种倒退的方式)如何删除元素。

                      希望对您有所帮助,或至少引导您朝着正确的方向前进。

                      【讨论】:

                      • 谢谢,mylist[i]
                      • 这对我不起作用。我得到:Error in list[length(list)] &lt;- NULL : replacement has length zero
                      • @Aleksandr Levchuck 的帖子告诉我,我实际上是在处理一个向量并且需要创建一个新对象
                      • 这是一个很好的捷径,但在我看来,@Kim 使用within 的回答将是删除列表元素的“正确”方式,因为它允许使用字符串来识别列表元素,可以同时移除多个元素,不需要原地完成。我是否遗漏了一些东西(除了 OP 的问题是关于删除单个元素的事实)?谢谢。
                      猜你喜欢
                      • 2021-03-10
                      • 1970-01-01
                      • 2011-04-20
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-08-06
                      • 2017-03-05
                      相关资源
                      最近更新 更多