我有一个简单的案例类:
case class OneTwo (one: String, two: String)
我有一个这个案例类的简单列表:
val list = List(Set(OneTwo("a", "b")), Set(OneTwo("a", "b"), OneTwo("c", "d")), Set(OneTwo("e", "f")))
现在我有一个不寻常的"独特的"此列表中的要求:如果一个集合包含在另一个集合中,它们是相等的,幸存者应该是较小的集合。例如。在上面list
" ditsinct"程序应返回List(Set(OneTwo("a", "b")), Set(OneTwo("e", "f")))
,因为Set(OneTwo("a", "b"))
包含在Set(OneTwo("a", "b"), OneTwo("c", "f"))
中且Set(OneTwo("a", "b"))
的尺寸较小。
现在,以下内容适用于REPL和编译,(参见"但是"稍后):
def ord: Ordering[Set[OneTwo]] = new Ordering[Set[OneTwo]]() {
def compare(set1: Set[OneTwo], set2: Set[OneTwo]): Int = {
if (set1.equals(set2) || set1.subsetOf(set2) || set2.subsetOf(set1)) 0 else if (set1.size != set2.size) set1.size compare set2.size else
set1.hashCode compare set2.hashCode
}
}
val listSorted = list.sorted(ord).reverse
val listDistinct = collection.immutable.SortedSet(listSorted: _*)(ord).toList
listDistinct
给出:
List[scala.collection.immutable.Set[OneTwo]] = List(Set(OneTwo(e,f)), Set(OneTwo(a,b)))
BUT:
这种排序违反了排序的传递性要求,因此在运行时会抛出java.lang.IllegalArgumentException: Comparison method violates its general contract!
例外。
很明白为什么:
scala> ord.compare(Set(OneTwo("a","b")), Set(OneTwo("e", "f")))
res56: Int = -1
scala> ord.compare(Set(OneTwo("e","f")), Set(OneTwo("a", "b"), OneTwo("c", "d")))
res57: Int = -1
scala> ord.compare(Set(OneTwo("a","b")), Set(OneTwo("a", "b"), OneTwo("c", "d")))
res58: Int = 0
这意味着A< B,B< C还有A = C.问题。
底线:有什么方法可以对我的OneTwo案例类列表做我想做的事情吗? (我不关心这个列表的最终顺序,也可能会产生一个Set,并且它不一定与我的策略类似)
答案 0 :(得分:2)
这是一个简单的解决方案,我确信有更优雅的方法:
list.sortBy(_.size).foldLeft(Set.empty[Set[OneTwo]])((res, set) => {
if (res.exists(_.subsetOf(set))) res else res + set
}).toList
按大小排序非常重要,因为较小的组会以这种方式显示在前面。之后,只需折叠列表,只需添加元素即可满足约束条件。请注意,我们会在Set
中累积结果,而不是List
,因为它使约束检查更简单,更有效。