0
\$\begingroup\$

What is the best way, in terms of performance, to remove a list (a group of elements such as integers or strings) from another list, other than using for or foreach loops?

For example, is there a function that takes a list as a parameter and removes every element in it?, similar to List.AddRange(), which takes a list as a parameter and adds every element from it.

public class ListsManager : MonoBehaviour
{
    [SerializeField] private List<int> _list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9, 10 };
    [SerializeField] private List<int> _listToRemove = new List<int>() { 1, 3, 5, 7, 9 };

    void Start()
    {
        for (int i = 0; i < _listToRemove.Count; i++)
        {
            _list.Remove(_listToRemove[i]);
        }
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ Does this answer your question? Remove items from one list in another \$\endgroup\$ Commented Dec 11, 2024 at 0:07
  • \$\begingroup\$ I think no because the method in this answer depends on creating a new list which will consume more memory \$\endgroup\$ Commented Dec 11, 2024 at 0:19
  • 1
    \$\begingroup\$ Note that there is more than one answer at that link, including several that do not allocate a new list. You have a menu of options to choose from here. Is there a specific criterion you have that no answer posted at this link satisfies? \$\endgroup\$ Commented Dec 11, 2024 at 1:15
  • 1
    \$\begingroup\$ Is this a theoretical problem or do you have a performance issue based related to list filtering? Depending on your context it might be the case that lists are the wrong data structure for the underlying task. What are you doing with the lists? How large are they? How often do they change & by how much? Describing your actual problem is more likely to yield an actual solution. \$\endgroup\$ Commented Dec 11, 2024 at 2:36

2 Answers 2

2
\$\begingroup\$

To remove elements from one list using another list in C#, you can use the RemoveAll method with a lambda. It's clean and avoids manual loops. Here's an example:

using System.Collections.Generic;
using UnityEngine;

public class ListsManager : MonoBehaviour {

    [SerializeField]
    private List<int> _list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9, 10 }; 

    [SerializeField]  
    private List<int> _listToRemove = new List<int>() { 3, 4, 7 }; 

    private void Start() { 

        _list.RemoveAll(item => _listToRemove.Contains(item)); 

        Debug.Log(string.Join(", ", _list));
        // Outputs: 1, 2, 5, 8, 9, 10 
    }
} 
\$\endgroup\$
2
  • \$\begingroup\$ Note that this solution is one of the ones already offered via the StackOverflow link shared in the comments. \$\endgroup\$ Commented Dec 11, 2024 at 13:05
  • \$\begingroup\$ While this avoids manual loops, behind the scene this is still a nested loop process (as described here. It is cleaner & probably easier to maintain. From a performance standpoint though, it simply pushes the looping behind the method call. \$\endgroup\$ Commented Dec 11, 2024 at 14:02
2
\$\begingroup\$

No matter what fancy syntax features you are using, this is always going to be an operation with an algorithmic complexity of \$O(n * m)\$ (with n and m being the sizes of the respective lists). With two unordered lists, there is no way around iterating every single element of the first list and comparing it with every single element of the second. So no matter if you use RemoveAll, a LINQ function or write the algorithm on your own, you will achieve micro-optimizations at best.

However, if you change the type of the _list from a List to a SortedSet or HashSet, then you can do this:

_set.ExceptWith(_listToRemove);

The ExceptWith(IEnumerable<T> other) method of both SortedSet and HashSet "is an \$O(n)\$ operation, where n is the number of elements in the other parameter.".

If you are not sure which flavor of ISet is more appropriate for your use-case, check this question on Stackoverflow (there is also a lot of interesting debate in the comments on the answers).

\$\endgroup\$
1
  • \$\begingroup\$ I was hoping OP might add more information to their question in response to Pikalek"s comment. If their range of items is as small as indicated in the example, with no duplicates, they might even be able to go with bitmasks instead of lists, and perform the set subtraction in constant time. (Unlikely to matter unless they're doing thousands of set subtractions in a frame, but I recently worked on a game project where I had to do just that for an automated puzzle solver, so game use cases exist) \$\endgroup\$ Commented Dec 12, 2024 at 12:40

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.