375

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.

2
  • Depends do you want to remove it by value e.g. "the value 5", or by index/indices "the element at index 5" or "at indices c(5:6,10)? If you want to remove by value and there are duplicates, then do you want to remove only the duplicates, first or last occurrence, or all? Is it guaranteed that the list contains your element/index? Do we need to handle the case where the list is empty? Do we need to ensure NA is passed (/excluded)? Is the list guaranteed to be flat or can it be nested? How many laters deep? Commented Aug 23, 2018 at 0:37
  • 5
    setdiff(myList,elementToRemove) Commented Sep 19, 2018 at 13:48

21 Answers 21

307
Answer recommended by R Language Collective

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 
Sign up to request clarification or add additional context in comments.

2 Comments

Your logical index only works if you have that single item "b" in a list element. You cannot remove , say, x$b that way, nor can you remove "b" from a list element x[[2]] = c("b","k") .
Regarding single vs multiple items: you could use %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?
255

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.

4 Comments

Thanks, mylist[i] <- NULL is exactly the way to do it.
This did not work for me. I get: Error in list[length(list)] <- NULL : replacement has length zero
@Aleksandr Levchuck 's post showed me that I was actually dealing with a vector and needed to create a new object
This is a great shortcut, but it seems to me like @Kim's answer using within 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.
79

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.

2 Comments

To do multiple within(l, rm(a, b))
To do multiple from a character vector: x <- c("a","b"); within(l,rm(list=x))
41

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)] 
  • Work for lists and vectors

2 Comments

@krlmlr: on the contrary, this solution is more general than Florian's answer, as it is polymorphic in the type of the collection.
@DanBarowy: I was wrong: This seems to be a synthesis of Chad's answer (the accepted one) and Florian's... A good brief summary, though.
25

Removing Null elements from a list in single line :

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

Cheers

2 Comments

This code breaks when x is an empty list. Use compact from plyr for this task instead.
Also if there are no nulls in the list, -(which(sapply(x,is.null),arr.ind=TRUE)) returns named integer(0) which will drop that row entirely.
20

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)

Comments

17

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 

Comments

12

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 

Comments

10

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]] 

1 Comment

Good answer! However, I think the [[-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].
8

Just wanted to quickly add (because I didn't see it in any of the answers) that, for a named list, you can also do l["name"] <- NULL. For example:

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

Comments

4

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 

Comments

4

tidyverse

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 

3 Comments

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!
yes, it returns "b", "c", which is what I'm trying to do. But oddly, in my R Shiny app it was returning "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.
4

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 

Comments

3

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" 

1 Comment

This only works if the list has a "b" item
2

You can also negatively index from a list using the extract function of the magrittr package to remove a list item.

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 

Comments

0

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" 

Comments

0

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 

Comments

0

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

Comments

-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 

2 Comments

m is a vector, not a list
The method does work for lists, but OP is lucky and probably wants some more parentheses: m[1:(length(m) - 1)]
-1

You can use which.

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

Comments

-1

if you'd like to avoid numeric indices, you can use

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

to delete names namea...namen from a. this works for lists

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

as well as for vectors

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.