Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable set in .NET

Does the .NET BCL have an immutable Set type? I'm programming in a functional dialect of C# and would like to do something like

new Set.UnionWith(A).UnionWith(B).UnionWith(C)

But the best I can find is HashSet.UnionWith, which would require the following sequence of calls:

HashSet composite = new HashSet();
composite.UnionWith(A);
composite.UnionWith(B);
composite.UnionWith(C);

This use is highly referentially opaque, making it hard to optimize and understand. Is there a better way to do this without writing a custom functional set type?

like image 560
David Albrecht Avatar asked Nov 08 '10 21:11

David Albrecht


2 Answers

The new ImmutableCollections have:

  • ImmutableStack<T>
  • ImmutableQueue<T>
  • ImmutableList<T>
  • ImmutableHashSet<T>
  • ImmutableSortedSet<T>
  • ImmutableDictionary<K, V>
  • ImmutableSortedDictionary<K, V>

More info here

About the union this test passes:

[Test]
public void UnionTest()
{
    var a = ImmutableHashSet.Create("A");
    var b = ImmutableHashSet.Create("B");
    var c = ImmutableHashSet.Create("C");
    var d = a.Union(b).Union(c);
    Assert.IsTrue(ImmutableHashSet.Create("A", "B", "C").SetEquals(d));
}
like image 100
Johan Larsson Avatar answered Oct 24 '22 02:10

Johan Larsson


Update

This answer was written some time ago, and since then a set of immutable collections have been introduced in the System.Collections.Immutable namespace.

Original answer

You can roll out your own method for this:

public static class HashSetExtensions {
  public static HashSet<T> Union<T>(this HashSet<T> self, HashSet<T> other) { 
    var set = new HashSet<T>(self); // don't change the original set
    set.UnionWith(other);
    return set;
  }
}

Use it like this:

var composite = A.Union(B).Union(C);

You can also use LINQ's Union, but to get a set, you'll need to pass the result to the HashSet constructor:

var composite = new HashSet<string>(A.Union(B).Union(C));

But, HashSet itself is mutable. You could try to use F#'s immutable set.

Also, as mentioned in the comments by ErikE, using Concat yields the same result and probably performs better:

var composite = new HashSet<string>(A.Concat(B).Concat(C));
like image 29
Jordão Avatar answered Oct 24 '22 03:10

Jordão