Dyland
Dyland

Reputation: 93

Iterating and Removing From a Set - Possible or Not?

I don't have a specific piece of code that I want looked at; however, I do have a question that I can't seem to get a straight, clear answer.

Here's the question: if I have a set, I can iterate over it in a for loop. As I iterate over it can I remove specific numbers using .remove() or do I have to convert my set to a list first? If that is the case, why must I convert it first?

Upvotes: 3

Views: 1075

Answers (3)

CryptoFool
CryptoFool

Reputation: 23099

This is how I'd do this:

myset = ...
newset = set()
while myset:
    v = myset.pop()
    if not do_i_want_to_delete_this_value(v):
        newset.add(v)
myset = newset

A list comprehension will work too:

myset = set([x for x in myset if not do_i_want_to_delete_this_value(x)])

But this gets messy if you want to do other stuff while you're iterating and you don't want to wrap all that logic in a single function call. Nothing wrong with doing that though.

myset = set([x for x in myset if process_element(x)])

process_element() just has to return True/False to say if the element should be removed from the set.

Upvotes: 1

s3cur3
s3cur3

Reputation: 3025

@nathancy has already given a good explanation as to why deleting during iteration won't work, but I'd like to suggest an alternative: instead of doing the deletion at the same time as you iterate, do it instead as a second stage. So, you'd instead:

  1. Iterate over your set to decide what you want to delete, and store the collection of things to be deleted separately.
  2. Iterate over your to-be-deleted collection and removing each item from the original set.

For instance:

def should_be_deleted(num):
    return num % 2 == 0

my_set = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
to_delete = []
for value in my_set:
    if should_be_deleted(value):
        to_delete.append(value)

for value in to_delete:
    my_set.remove(value)

print(my_set)

Prints:

set([1, 3, 5, 7, 9])

The same pattern can be applied to delete from any collection—not just set, but also list, dict, etc.

Upvotes: 1

nathancy
nathancy

Reputation: 46620

In both cases, you should avoid iterating and removing items from a list or set. It's not a good idea to modify something that you're iterating through as you can get unexpected results. For instance, lets start with a set

numbers_set = {1,2,3,4,5,6}
for num in numbers_set:
    numbers_set.remove(num)
print(numbers_set)

We attempt to iterate through and delete each number but we get this error.

Traceback (most recent call last):
  File ".\test.py", line 2, in <module>
    for num in numbers_set:
RuntimeError: Set changed size during iteration

Now you mentioned "do I have to convert my set to a list first?". Well lets test it out.

numbers_list = [1,2,3,4,5,6]
for num in numbers_list:
    print(num)
    numbers_list.remove(num)
print(numbers_list)

This is the result:

[2, 4, 6]

We would expect the list to be empty but it gave us this result. Whether you're trying to iterate through a list or a set and delete items, its generally not a good idea.

Upvotes: 1

Related Questions