Давайте иметь этот класс C # (это будет почти то же самое в 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;
}
}
Как видите, равенство двух экземпляров MyClass
зависит A
только от. Таким образом, могут быть два экземпляра, которые равны, но содержат различную информацию в своем B
свойстве.
В стандартной библиотеке коллекций многих языков (включая, конечно, C # и Java) есть Set
( HashSet
в C #) коллекция, которая может содержать не более одного элемента из каждого набора равных экземпляров.
Можно добавлять элементы, удалять элементы и проверять, содержит ли набор элемент. Но почему невозможно получить конкретный предмет из набора?
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
Единственный способ получить мой элемент - это перебрать всю коллекцию и проверить все элементы на равенство. Однако O(n)
вместо этого требуется время O(1)
!
До сих пор я не нашел ни одного языка, который бы поддерживал набор. Все «общие» языки, которые я знаю (Java, C #, Python, Scala, Haskell ...), выглядят одинаково: вы можете добавлять элементы, но не можете их извлекать. Есть ли веская причина, почему все эти языки не поддерживают что-то такое простое и очевидно полезное? Они не могут быть просто не правы, верно? Есть ли языки, которые поддерживают это? Может быть, получение определенного предмета из набора неправильно, но почему?
Есть несколько связанных с этим вопросов SO:
/programming/7283338/getting-an-element-from-a-set
/programming/7760364/how-to-retrieve-actual-item-from-hashsett
Set<E>
реализации находятся только Map<E,Boolean>
внутри.
a == b
всегда верно) на всякий случай this.A == null
. if (item == null || this.A == null || item.A == null)
Тест «перестарались» и проверяет много, возможно , для того , чтобы искусственно создать «высокого качества» кода. Я вижу этот вид «перепроверки» и все время слишком корректен в Code Review.
std::set
поддерживает поиск объектов, поэтому не все «общие» языки такие, как вы описали.