Могу ли я создать коллекцию в Scala, которая использует разные реализации equals/hashCode/compare?

Я ищу как простой способ создать набор идентификаторов. Я просто хочу иметь возможность отслеживать, «видел» ли я конкретный объект при обходе графика.

Я не могу использовать обычный Set, потому что Set использует "==" (метод equals в Scala) для сравнения элементов. То, что я хочу, это набор, который использует «eq».

Есть ли способ создать набор в Scala, который использует какой-то определенный приложением метод для проверки равенства, а не вызывает равенство для элементов набора? Я искал какой-то метод "wrapEquals", который я мог бы переопределить, но не нашел.

Я знаю, что мог бы использовать Java IdentityHashMap, но я ищу что-то более универсальное.

Еще одна идея, которая у меня была, заключалась в том, чтобы просто обернуть каждый элемент набора в другой объект, который реализует equals в терминах eq, но было бы расточительно генерировать тонны новых объектов только для того, чтобы получить новую реализацию equals.

Спасибо!


person Willis Blackburn    schedule 18.04.2010    source источник


Ответы (3)


Это аналогичный вопрос. Принятым ответом в этом случае было использование TreeSet и предоставление пользовательского Comparator.

person Ben Lings    schedule 18.04.2010

В зависимости от ваших потребностей вы можете создать поле, для которого вы используете проверки личности на содержащемся элементе, например:

class IdentBox[T <: AnyRef](val value: T) {

    override def equals(other: Any): Boolean = other match {
      case that: IdentBox[T] => that.value eq this.value
      case _ => false
    }

    override def hashCode(): Int = value.hashCode

  }

И сделайте так, чтобы коллекция содержала эти блоки, а не элементы напрямую: Set[IdentBox[T]]

У него есть некоторые накладные расходы на упаковку/распаковку, но это может быть терпимо в вашем случае использования.

person Miquel    schedule 28.11.2016
comment
Предоставленный вами hashCode работает (на самом деле любой хэш будет работать, если он возвращает одно и то же значение для одного и того же экземпляра), но, возможно, System.identityHashCode(value) будет работать лучше? - person Suma; 05.01.2018
comment
Я не уверен в этом, учитывая комментарий Уиллиса Блэкберна в другом ответе на этот вопрос: К сожалению, System.identityHashCode возвращает значение хэш-кода по умолчанию, а не адрес, поэтому два разных объекта могут иметь одно и то же значение identityHashCode. - person Miquel; 07.01.2018
comment
identityHashCode — это 32-битное значение (int), поэтому оно не гарантируется (и не может быть) уникальным на 64-битной JVM. Тем не менее, он, скорее всего, более уникален, чем hashValue, который был разработан для взаимодействия с равенством значений case class, которое вы используете сейчас. В вашем случае все работает, так как вы не будете использовать identityHashCode для выполнения сравнения, а только в качестве хэша для сопровождения сравнения на основе eq. - person Suma; 07.01.2018

Поскольку вам не требуется ссылка на «увиденные» объекты, а просто логическое значение для «содержит», я бы предложил просто использовать mutable.Set[Int] и загрузить его значениями, полученными при вызове System.identityHashCode(obj).

Пользовательские коллекции Scala имеют достаточную концептуальную площадь поверхности, чтобы отпугнуть большинство людей, которым нужна такая быстрая настройка.

person Mitch Blevins    schedule 19.04.2010
comment
К сожалению, System.identityHashCode возвращает значение хеш-кода по умолчанию, а не адрес, поэтому два разных объекта могут иметь одно и то же значение identityHashCode. Это может работать в 32-битной JVM, но в 64-битной JVM должны быть некоторые конфликты. - person Willis Blackburn; 19.04.2010
comment
Это проблема только в том случае, если вы хотите, чтобы ваше программное обеспечение работало каждый раз. :-) - person Mitch Blevins; 19.04.2010