Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I preallocate a hashset<T>

Tags:

c#

hashset

Why can't I preallocate a hashset<T>?

There are times when i might be adding a lot of elements to it and i want to eliminate resizing.

like image 516
Ryan Lee Avatar asked Jul 21 '11 06:07

Ryan Lee


People also ask

How do you make a HashSet case insensitive?

set. Any(s => string. Equals(s, item, StringComparison. OrdinalIgnoreCase));

Does HashSet allow duplicates C#?

Thus, HashSet is a generic collection, that does not allow duplicates. We can use HashSet to remove the duplicates from any collection like the List, using HashSet.

What is default capacity of HashSet in Java?

Constructs a new, empty set; the backing HashMap instance has default initial capacity (16) and load factor (0.75).


2 Answers

Answer below was written in 2011. It's now in .NET 4.7.2 and .NET Core 2.0; it will be in .NET Standard 2.1.


There's no technical reason why this shouldn't be possible - Microsoft just hasn't chosen to expose a constructor with an initial capacity.

If you can call a constructor which takes an IEnumerable<T> and use an implementation of ICollection<T>, I believe that will use the size of the collection as the initial minimum capacity. This is an implementation detail, mind you. The capacity only has to be large enough to store all the distinct elements...

EDIT: I believe that if the capacity turns out to be way larger than it needs to be, the constructor will trim the excess when it's finished finding out how many distinct elements there really are.

Anyway, if you have the collection you're going to add to the HashSet<T> and it implements ICollection<T>, then passing it to the constructor instead of adding the elements one by one is going to be a win, basically :)

EDIT: One workaround would be to use a Dictionary<TKey, TValue> instead of a HashSet<T>, and just not use the values. That won't work in all cases though, as it won't give you the same interface as HashSet<T>.

like image 65
Jon Skeet Avatar answered Sep 19 '22 15:09

Jon Skeet


The answer by Jon Skeet is almost a complete one. To solve this problem with HashSet<int> I had to do the following:

public class ClassUsingHashSet {     private static readonly List<int> PreallocationList         = Enumerable.Range(0, 10000).ToList();      public ClassUsingHashSet()     {         this.hashSet = new HashSet<int>(PreallocationList);         this.hashSet.Clear();     }      public void Add(int item)     {         this.hashSet.Add(item);     }      private HashSet<int> hashSet; } 

This trick works because after Clear the HashSet is not trimmed, as described in the documentation:

The capacity remains unchanged until a call to TrimExcess is made.

like image 31
BartoszKP Avatar answered Sep 20 '22 15:09

BartoszKP