What is a Java set get method?

582    Asked by NeerajNair in Java , Asked on Oct 12, 2022

 Let's have this C# class (it would be almost the same in Java)

public class MyClass {
   public string A {get; set;}
   public string B {get; set;}
   public override bool Equals(object obj) {
        var item = obj as MyClass;
        if (item == null || this.A == null || item.A == null)
        {
            return false;
        }
        return this.A.equals(item.A);
   }
   public override int GetHashCode() {
        return A != null ? A.GetHashCode() : 0;
   }
}

As you can see, equality of two instances of MyClass depends on A only. So there can be two instances that are equal, but holding different pieces of information in their B property.

In a standard collection library of many languages (including C# and Java, of course) there is a Set (HashSet in C#), which is a collection, which can hold at most one item from each set of equal instances.

One can add items, remove items and check if the set contains an item. But why is it impossible to get a particular item from the set?

HashSet set = new HashSet();
mset.Add(new MyClass {A = "Hello", B = "Bye"});
//I can do this
if (mset.Contains(new MyClass {A = "Hello", B = "See you"})) {
    //something
}
//But I cannot do this, because Get does not exist!!!
MyClass item = mset.Get(new MyClass {A = "Hello", B = "See you"});

Console.WriteLine(item.B); //should print Bye

The only way to retrieve my item is to iterate over the whole collection and check all items for equality. However, this takes O(n) time instead of O(1)!

I haven't found any language that supports get from a set so far. All "common" languages I know (Java, C#Python, Scala, Haskell...) seem to be designed in the same way: you can add items, but you cannot retrieve them. Is there any good reason why all these languages do not support something that is easy and obviously useful? They cannot be just all wrong, right? Are there any languages that do support it? Maybe retrieving a particular item from a set is wrong, but why?


Answered by Neeraj Thakur

Your problem regarding the Java set get method is that you have two contradictory concepts of equality:


actual equality, where all fields are equal

set membership equality, where only A is equal

If you would use the actual equality relation in your set, the problem of retrieving a particular item from the set doesn't arise – to check whether an object is in the set, you already have that object. It is therefore never necessary to retrieve a particular instance from a set, assuming you are using the correct equality relation.

We could also argue that a set is an abstract data type that is defined purely by the S containing x or x is-element-of S relation (“characteristic function”). If you want other operations, you're not actually looking for a set.

What happens quite often – but what is not a set – is that we group all objects into distinct equivalence classes. The objects in each such class or subset are only equivalent, not equal. We can represent each equivalence class through any member of that subset, and it then becomes desirable to retrieve that representing element. This would be a mapping from the equivalence class to the representative element.

In C#a dictionary can use an explicit equality relation, I think. Otherwise, such a relation can be implemented by writing a quick wrapper class. Pseudocode:

// The type you actually want to store

class MyClass { ... }
// A equivalence class of MyClass objects,
// with regards to a particular equivalence relation.
// This relation is implemented in EquivalenceClass.Equals()
class EquivalenceClass {
  public MyClass instance { get; }
  public override bool Equals(object o) { ... } // compare instance.A
  public override int GetHashCode() { ... } // hash instance.A
  public static EquivalenceClass of(MyClass o) { return new EquivalenceClass { instance = o }; }
}
// The set-like object mapping equivalence classes
// to a particular representing element.
class EquivalenceHashSet {
  private Dictionary dict = ...;
  public void Add(MyClass o) { dict.Add(EquivalenceClass.of(o), o)}
  public bool Contains(MyClass o) { return dict.Contains(EquivalenceClass.of(o)); }
  public MyClass Get(MyClass o) { return dict.Get(EquivalenceClass.of(o)); }
}


Your Answer

Interviews

Parent Categories