Miejmy tę klasę C # (w Javie byłoby prawie tak samo)
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;
}
}
Jak widać, równość dwóch przypadków MyClass
zależy A
tylko od. Mogą więc istnieć dwa przypadki, które są równe, ale zawierają inną informację w swojej B
właściwości.
W standardowej bibliotece wielu języków (w tym oczywiście C # i Java) znajduje się Set
( HashSet
w C #) kolekcja, która może pomieścić maksymalnie jeden element z każdego zestawu równych instancji.
Można dodawać elementy, usuwać elementy i sprawdzać, czy zestaw zawiera element. Ale dlaczego nie można zdobyć określonego przedmiotu z zestawu?
HashSet<MyClass> mset = new HashSet<MyClass>();
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
Jedynym sposobem na odzyskanie mojego przedmiotu jest iteracja całej kolekcji i sprawdzenie, czy wszystkie elementy są równe. To jednak wymaga O(n)
czasu zamiast O(1)
!
Do tej pory nie znalazłem żadnego języka, który obsługuje pobieranie z zestawu. Wszystkie „popularne” języki, które znam (Java, C #, Python, Scala, Haskell ...) wydają się być zaprojektowane w ten sam sposób: możesz dodawać elementy, ale nie możesz ich odzyskać. Czy jest jakiś dobry powód, dla którego wszystkie te języki nie obsługują czegoś tak łatwego i oczywiście przydatnego? Nie mogą się wszyscy mylić, prawda? Czy są jakieś języki, które to obsługują? Może wycofywanie określonego elementu z zestawu jest złe, ale dlaczego?
Istnieje kilka powiązanych pytań SO:
/programming/7283338/getting-an-element-from-a-set
/programming/7760364/how-to-retrieve-actual-item-from-hashsett
Set<E>
implementacji jest tylko Map<E,Boolean>
w środku.
a == b
zawsze prawda) w przypadku this.A == null
. if (item == null || this.A == null || item.A == null)
Test jest „przesadzone” i sprawdza się dużo, być może w celu stworzenia sztucznie „wysokiej jakości” kod. Widzę tego rodzaju „sprawdzanie” i nadmierną poprawność w Code Review.
std::set
obsługuje pobieranie obiektów, więc nie wszystkie „powszechne” języki są takie, jak opisano.