9

我刚刚偶然发现了 Tony Morris 的一篇关于 Java 的博客文章以及该语言的一个基本问题:为集合定义定制的相等关系。我认为这是一件大事,并想知道是否有一些 scala 解决方案。

经典问题体现在对交易的思考中。假设我进行了两次 +100 沃达丰股票 @150p 的交易。这两个交易是平等的,是吗?除了他们不是同一个行业。在一个正常的现实世界系统的情况下,具有持久性或序列化,我不能依靠身份来告诉我两个引用是否指向同一个交易

所以我想要的是能够创建一个集合,我可以将 Equality-relation 传递给:

val as = CleverSet[Trade](IdEquality)
val bs = CleverSet[Trade](EconomicsEquality)

我将如何以有效的方式实现我的集合(除非EqualityRelation还定义了一种hash机制)?

trait EqualityRelation[T] {
  def equal(t1: T, t2: T) : Boolean
  def hash(t: T) : Int
}

所以问题是:

  • 有没有提供这种能力的图书馆?
  • 有没有办法在 Scala 中巧妙地做到这一点?

似乎使用隐式,添加到现有的 scalaSet类型将是一件很容易的事情。

4

3 回答 3

7

这已经可以通过 Java 的 TreeSet 和 Comparator 实现来实现:

TreeSet<String> ignoreCase = new TreeSet<String>(new Comparator<String>(){
    @Override
    public int compare(String o1, String o2) {
        return o1.compareToIgnoreCase(o2);
    }});

TreeSet<String> withCase = new TreeSet<String>();

List<String> values = asList("A", "a");
ignoreCase.addAll(values);
withCase.addAll(values);

输出:

ignoreCase -> [A]
withCase -> [A, a]

这样做的缺点是要实现的 Comparator 比需要的更强大,并且您仅限于支持 Comparator 的集合。正如 oxbow_lakes 所指出的, Comparator 实现打破了 Set 合同(因为!a.equals(b)它可能是那个new Set(); set.add(a) == true && set.add(b) == false)。

Scala 通过 A => Ordered[A] 的视图转换来支持这一点。

scala> new scala.collection.immutable.TreeSet[String]()(x=> x.toLowerCase) + "a"
 + "A"
res0: scala.collection.immutable.TreeSet[String] = Set(A)
于 2010-02-26T13:35:31.447 回答
3

我知道您在询问 Scala,但值得与 .Net 集合提供的内容进行比较。特别是,所有基于哈希的集合(例如Dictionary<TKey, TValue>HashSet<T>)都可以采用IEqualityComparer<T>. 这类似于 Scala 的Equiv[T],但也提供了自定义哈希码。您可以通过子类化创建类似的特征Equiv

trait HashEquiv[T] extends Equiv[T] {
  def hashOf(t: T) : Int
}

为了得到完全支持,基于散列的集合需要在HashEquiv它们的构造中添加隐式参数,并使用隐式导入的equivandhashOf方法而不是Object实例方法(如TreeSet, 等使用Orderedtrait,但反过来)。还需要使用内在和Any实现的隐式转换。HashEquivequalshashCode

于 2010-02-26T22:06:14.097 回答
2

您正在描述散列策略的概念。Trove 库包括可以使用散列策略构建的集合和映射。

于 2010-02-26T13:40:16.467 回答