Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

looking for something like a HashSet for tuples in arbitrary order

Discussion in 'Scripting' started by my_password_is_my_username, May 2, 2022.

  1. my_password_is_my_username

    my_password_is_my_username

    Joined:
    Oct 7, 2021
    Posts:
    12
    Hi,

    I need to store some data on point connections between two Vector3 coordinates. I thought of using a HashSet with a tuple of the points A and B as key to store the connection object. However I don't know in which order the points in the tuple will be stored. Is there an elegant way of telling the set that tuple (A, B) and (B, A) are equivalent or is there a better data structure for this?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,384
    HashSet takes a IEqualityComparer as an argument of its constructor:
    https://docs.microsoft.com/en-us/do...-collections-generic-iequalitycomparer((-0)))

    Implement your own comparer that evaluates these tuples as equal, pass it in when creating the HashSet, done.

    Most of the built in collections support this equality comparer functionality, allowing the collection to consume one to override how the collection determines if it contains an element. One of the exceptions being List, despite it being the most commonly used collection.

    You can also of course implement your own struct data type with both Vectors as fields and implement its equality to do the same as well.

    [edit]

    Oh, you better make sure that the 'GetHashCode' implementation of the equality comparer evaluates the same hashcode regardless of the vector orders. A,B should equal B,A.

    Otherwise the HashSet will put them in different buckets since its implemented assuming equal elements have equal hashcodes.

    Something like:
    Code (csharp):
    1. public int GetHashCode(ValueTuple<Vector3, Vector3> tuple) => tuple.Item1.GetHashCode() ^ tuple.Item2.GetHashCode();
    This should work since XOR is commutative and doesn't care the order of Item1 and Item2.

    ...

    With all this said you may run into oddities since vectors rely on float, and float equivalency is problematic at best. If you think you're going to deal with that float error via the Equals method of this equality comparer, you can... but again, make sure that the hashcode also accounts for it as well.

    And don't do it by just returning the same number for all values (like say 0), because you just turned your HashSet into an O(N) contains collection completely defeating the purpose of it.
     
    Last edited: May 3, 2022
  3. my_password_is_my_username

    my_password_is_my_username

    Joined:
    Oct 7, 2021
    Posts:
    12
    Thanks for the detailed answer, I will dive into that!