I have a list and I want to remove a single element from it. How can I do this?
I've tried looking up what I think the obvious names for this function would be in the reference manual and I haven't found anything appropriate.
I have a list and I want to remove a single element from it. How can I do this?
I've tried looking up what I think the obvious names for this function would be in the reference manual and I haven't found anything appropriate.
If you don't want to modify the list in-place (e.g. for passing the list with an element removed to a function), you can use indexing: negative indices mean "don't include this element".
x <- list("a", "b", "c", "d", "e") # example list x[-2] # without 2nd element x[-c(2, 3)] # without 2nd and 3rd Also, logical index vectors are useful:
x[x != "b"] # without elements that are "b" This works with dataframes, too:
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 x$b that way, nor can you remove "b" from a list element x[[2]] = c("b","k") .%in% for testing against multiple items. I’m not sure what you mean by “cannot remove x$b” – do you mean removing the whole column b?I don't know R at all, but a bit of creative Googling led me here: http://tolstoy.newcastle.edu.au/R/help/05/04/1919.html
The key quote from there:
I do not find explicit documentation for R on how to remove elements from lists, but trial and error tells me
myList[[5]] <- NULL
will remove the 5th element and then "close up" the hole caused by deletion of that element. That suffles the index values, So I have to be careful in dropping elements. I must work from the back of the list to the front.
A response to that post later in the thread states:
For deleting an element of a list, see R FAQ 7.1
And the relevant section of the R FAQ says:
... Do not set x[i] or x[[i]] to NULL, because this will remove the corresponding component from the list.
Which seems to tell you (in a somewhat backwards way) how to remove an element.
Error in list[length(list)] <- NULL : replacement has length zerowithin would be the "right" way to remove list elements, since it allows the use of character strings to identify list elements, can remove multiple elements simultaneously, and does not need to be done in place. Am I missing something (other than the fact that the OP's question was about removing a single element)? Thanks.I would like to add that if it's a named list you can simply use within.
l <- list(a = 1, b = 2) > within(l, rm(a)) $b [1] 2 So you can overwrite the original list
l <- within(l, rm(a)) to remove element named a from list l.
Here is how the remove the last element of a list in R:
x <- list("a", "b", "c", "d", "e") x[length(x)] <- NULL If x might be a vector then you would need to create a new object:
x <- c("a", "b", "c", "d", "e") x <- x[-length(x)] Removing Null elements from a list in single line :
x=x[-(which(sapply(x,is.null),arr.ind=TRUE))]
Cheers
x is an empty list. Use compact from plyr for this task instead.-(which(sapply(x,is.null),arr.ind=TRUE)) returns named integer(0) which will drop that row entirely.If you have a named list and want to remove a specific element you can try:
lst <- list(a = 1:4, b = 4:8, c = 8:10) if("b" %in% names(lst)) lst <- lst[ - which(names(lst) == "b")] This will make a list lst with elements a, b, c. The second line removes element b after it checks that it exists (to avoid the problem @hjv mentioned).
or better:
lst$b <- NULL This way it is not a problem to try to delete a non-existent element (e.g. lst$g <- NULL)
Use - (Negative sign) along with position of element, example if 3rd element is to be removed use it as your_list[-3]
Input
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 Remove single element from list
my_list[-3] # $`a` # [1] 3 # $b # [1] 3 # $d # [1] "Hello" # $e [1] NA Remove multiple elements from list
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 There's the rlist package (http://cran.r-project.org/web/packages/rlist/index.html) to deal with various kinds of list operations.
Example (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")) Results in:
# $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 Don't know if you still need an answer to this but I found from my limited (3 weeks worth of self-teaching R) experience with R that, using the NULL assignment is actually wrong or sub-optimal especially if you're dynamically updating a list in something like a for-loop.
To be more precise, using
myList[[5]] <- NULL will throw the error
myList[[5]] <- NULL : replacement has length zero
or
more elements supplied than there are to replace
What I found to work more consistently is
myList <- myList[[-5]] [[-5]] should be single square brackets, otherwise you are deselecting only the contents of that list element, not the element itself. Well, at least using double square brackets gives me this error: "attempt to select more than one element". What works for me was then: myList <- myList[-5].In the case of named lists I find those helper functions useful
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 There are several options from the purrr package:
Easily keep or discard by name or index
discard_at and keep_at allows you to keep elements by name OR position:
library(purrr) l <- list("a" = 1:2, "b" = 3:4, "d" = list("e" = 5:6, "f" = 7:8)) discard_at(l, "d") # $a # [1] 1 2 # # $b # [1] 3 4 keep_at(l, c("a", "b")) # $a # [1] 1 2 # # $b # [1] 3 4 Keep or discard with combination of name and index (works for nested lists)
pluck and assign_in work well with nested values and you can access it using a combination of names and/or indices:
# 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 Or you can remove values using modify_list by assigning zap() or NULL:
all.equal(list_modify(l, a = zap()), list_modify(l, a = NULL)) [1] TRUE Keep or discard using predicate function
You can remove or keep elements using a predicate function with discard and keep:
# remove numeric elements ("d" is a list) 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 pluck(l, "d", "e") <- NULL worked for me. I tried something like names(list(a = 1, b = 2, c = 3)[c("b", "c")]) to get rid of a, but in my shiny app i got NA, b, c. Your pluck statement actually deleted the a value. Thanks!"NA", "b", "c" during runtime. I spent an hour on that bug trying different ways to subset my list to the elements I wanted, but only your pluck method worked. It was very odd that I was getting a list with the name NA in it.keep_at() and discard_at() were added in purrr 1.1.0.Using lapply and 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))] # or library(purrr) lst |> discard_at("a") # works with vectors If you only want to remove the first occurrence of the element "b" and leave the rest
x <- c("a", "b", "b", "c", "d", "e") which(x == "b") # [1] 2 3 which(x == "b")[1] # [1] 2 x[-which(x == "b")[1]] # [1] "a" "b" "c" "d" "e" Assume that 'remove' means making it 'NULL' without changing the overall order.
mylist <- list("a", "b", "c", "d", "e", "f", "g") # remove rule (or) # 1. remove letter "e" & "f" # 2. remove the 2nd value mapply( \(x, y) if (x %in% c("e", "f") | y == 2) { NULL } else { x }, mylist, 1:length(mylist) ) # output: # [[1]] # [1] "a" # # [[2]] # NULL # # [[3]] # [1] "c" # # [[4]] # [1] "d" # # [[5]] # NULL # # [[6]] # NULL # # [[7]] # [1] "g" Here is a simple solution that can be done using base R. It removes the number 5 from the original list of numbers. You can use the same method to remove whatever element you want from a list.
#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 != remove){ new_list[[counter]] = n counter = counter + 1 } } The new_list variable no longer contains 5.
new_list # [1] 1 2 3 4 6 7 8 9 10 For a pipeable version of removing (or in general setting) list entries, you can use {magrittr}'s function inset() or inset2() (depending on if you would use 1 or 2 squared brackets, i.e. [<- or [[<-)
library(magrittr) list(a = 1, b = 2, c = 3, d = 4) %>% # remove (single) entry b by setting it NULL inset2('b', NULL) %>% # update entries c and d inset(c('c', 'd'), c(5, 6)) #> $a #> [1] 1 #> #> $c #> [1] 5 #> #> $d #> [1] 6 Created on 2025-02-18 with reprex v2.1.1
How about this? Again, using indices
> m <- c(1:5) > m [1] 1 2 3 4 5 > m[1:length(m)-1] [1] 1 2 3 4 or
> m[-(length(m))] [1] 1 2 3 4 m[1:(length(m) - 1)]