我偶然发现了Tony Morris的一个blog-posts about Java以及该语言的一个基本问题:为一个集合定义一个定制的平等关系。这是我认为是大不了的事情,并且想知道是否有一些scala解决方案。
经典问题表现在思考交易。假设我在@ 150p进行了两笔+100沃达丰股票交易。这两笔交易是平等的,是吗?除非他们不是相同的交易。对于普通的真实世界系统,使用持久性或序列化,我不能依赖身份来告诉我两个引用是否属于同一行业!
所以我想要的是能够创建一个我可以传递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 Set
类型会非常简单。
答案 0 :(得分:6)
这已经可以通过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]
这样做的缺点是比较器要实现的功能比需要的功能更强大,并且限制为支持比较器的集合。正如oxbow_lakes所指出的,Comparator实现违反了Set契约(!a.equals(b)
可能是new Set(); set.add(a) == true && set.add(b) == false
)。
Scala通过A =&gt;的视图转换支持此功能。有序[A]。
scala> new scala.collection.immutable.TreeSet[String]()(x=> x.toLowerCase) + "a"
+ "A"
res0: scala.collection.immutable.TreeSet[String] = Set(A)
答案 1 :(得分:2)
您正在描述哈希策略的概念。 Trove library包括可以使用散列策略构建的集合和映射。
答案 2 :(得分: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
隐式参数,并使用隐式导入的equiv
和hashOf
方法而不是Object
实例方法(如TreeSet
等)使用Ordered
特征,但反过来)。还需要使用内部Any
和HashEquiv
实现从equals
到hashCode
的隐式转换。