2010-02-26 46 views
8

我刚刚偶然发现了托尼·莫里斯的blog-posts about Java之一和语言的一个基本问题:为集合定义一个定制的平等关系。这是我认为是大交易,并想知道是否有一些scala解决方案。斯卡拉的平等关系

经典问题体现在思考交易。假设我做了两次150p沃达丰股份交易。这两个交易是平等的,是吗?除他们不是同行。在一个普通的真实系统的情况下,通过持久化或序列化,我不能依靠标识来告诉我两个引用是否是相同的交易

所以,我要的是能够创建一个集合,我可以通过一个平等,关系到:

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中整洁地做这件事的方法?

看来,有了暗示,将它添加到现有的scala Set类型将是一件相当容易的事情。

+0

在斯卡拉有相同的:http://github.com/scalaz/scalaz/blob/master/example/src/main/scala/scalaz/ExampleEqual.scala。但我不太熟悉,可以说明它的基础。 – 2010-02-26 13:23:27

+0

我认为这只是一个类型安全的平等,所以''你好“=== 2'不能编译 – 2010-02-26 16:20:46

+0

scalaz.Equal不只是类型安全,它也是一个灵活的。 'Equal [List [Foo]]]'可由'Equal [Foo]'参数化。这走向了你的目标的一半。马丁奥德斯基拒绝向标准库中添加哈希,他说“我们希望保持通用哈希,它是Java文化中太多的一部分。” http://www.scala-lang.org/node/4091#comment-16327 – retronym 2010-02-26 18:03:15

回答

6

这已经可以与Java的TreeSet中和比较方面取得:

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] 

这样做的缺点是实施比较更加强大比需要和你'限于支持比较器的集合。正如oxbow_lakes所指出的那样,比较器实现会破坏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) 
+1

而你被迫走下了树结构的O(log(n))访问时间的路线 – 2010-02-26 14:38:13

+0

另外,从JavaDoc的' TreeSet':*请注意,如果要正确实现Set接口*,则由集合维护的排序(无论是否提供显式比较器)必须与equals保持一致,所以看起来尽管此方法有效,但它并不“ t挺有感觉 – 2010-02-26 14:52:20

+0

这是一个有效的观点。打破一套合同是一个坏主意。如果你将这个TreeSet放在它的周围必须被包装。您建议的CleverSet会以相同的方式破坏它。它只能实现Iterable [T]而不是Set [T]。 – 2010-02-26 15:35:30

2

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

+0

感谢您的链接 – 2010-02-26 14:32:56

2

我知道你在问关于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隐含参数添加到他们的建筑和使用隐含进口equivhashOf方法,而不是Object实例方法(如TreeSet,等Ordered特性,但相反)。还需要从AnyHashEquiv的隐式转换,该转换使用固有的equalshashCode实现。