Skip to content

Perf: Use temporary set to to speed up list_update and list_difference_update - #4939

Open
nikolajmunk wants to merge 3 commits into
ManimCommunity:mainfrom
nikolajmunk:perf/faster-unique-lists
Open

Perf: Use temporary set to to speed up list_update and list_difference_update#4939
nikolajmunk wants to merge 3 commits into
ManimCommunity:mainfrom
nikolajmunk:perf/faster-unique-lists

Conversation

@nikolajmunk

@nikolajmunk nikolajmunk commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Overview: What does this pull request change?

This PR uses a set for the repeated membership test performed in list_update and list_difference_update to improve performance. I've also written tests for these functions, since none existed.

The new versions of both methods also explicitly support generator iterables, which is not currently the case despite the Iterable[T] type hints.

Motivation and Explanation: Why and how do your changes improve the library?

In their current implementations, both functions use this pattern:

return [e for e in l1 if e not in l2] # (and some other stuff)

Clearly, if l2 is a list, then the time complexity is O(len(l1) * len(l2)) in the worst case. This small change massively improves performance when l2 is large.

I wrote a quick script to benchmark the before and after, measured with cProfile:

def construct(self):
    self.foreground_mobjects = [Circle() for _ in range(10000)]
    group = Group()
    group.submobjects = [Triangle() for _ in range(1000)]
    anims = [Animation(mob) for mob in group]
    for _ in range(20):
        self.play(*anims)

Results with current implementation (total time 15.417 seconds):
image
Results with my implementation (total time 0.0232 seconds):
image
I haven't done a similar benchmark for small l2 but anecdotally, performance is more or less unchanged.

Links to added or changed documentation pages

Further Information and Comments

It seems that there are simply no tests for any of the utils/iterables methods? Let's hope the ones I wrote are a good enough start, then we can add more later :)

Reviewer Checklist

  • The PR title is descriptive enough for the changelog, and the PR is labeled correctly
  • If applicable: newly added non-private functions and classes have a docstring including a short summary and a PARAMETERS section
  • If applicable: newly added functions and classes are tested

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant