如标题中所述,我有一个具有自定义排序的SortedSet。该集合包含类 Edge 的对象(表示图形中的边缘(。每个 Edge 都有与之关联的成本以及起点和终点。
case class Edge(firstId : Int, secondId : Int, cost : Int) {}
我对 SortedSet 的边的排序如下所示(适用于 A* 算法(:
object Ord {
val edgeCostOrdering: Ordering[Edge] = Ordering.by { edge : Edge =>
if (edge.secondId == goalId) graphRepresentation.calculateStraightLineCost(edge.firstId, goalId) else edge.cost + graphRepresentation.calculateStraightLineCost(edge.secondId, goalId)
}
}
然而,在我将上述排序应用于集合并尝试对具有不同起点/终点但成本相同的边缘进行排序后 - 只有最后遇到的边保留在集合中。
例如:
val testSet : SortedSet[Edge] = SortedSet[Edge]()(edgeOrder)
val testSet2 = testSet + Edge(1,4,2)
val testSet3 = testSet2 + Edge(3,2,2)
println(testSet3)
仅打印件 (3,2,2(
这些不是不同的对象吗?它们只共享一个字段的相同值,因此 Set 不应该能够处理这个问题吗?
考虑改用mutable.PriorityQueue
,它可以保留具有相同顺序的多个元素。这是一个更简单的示例,我们按第二个组件对进行排序:
import collection.mutable.PriorityQueue
implicit val twoOrd = math.Ordering.by{ (t: (Int, Int)) => t._2 }
val p = new PriorityQueue[(Int, Int)]()(twoOrd)
p += ((1, 2))
p += ((42, 2))
即使两个对都映射到2
,因此具有相同的优先级,队列也不会丢失任何元素:
p foreach println
(1,2)
(42,2)
要在SortedSet
中保留所有具有相同排序成本值的不同Edge
,您可以修改Ordering.by
的函数以返回一个包含边缘 ID 的Tuple
:
val edgeCostOrdering: Ordering[Edge] = Ordering.by { edge: Edge =>
val cost = if (edge.secondId == goalId) ... else ...
(cost, edge.firstId, edge.secondId)
}
以下是概念的快速验证:
import scala.collection.immutable.SortedSet
case class Foo(a: Int, b: Int)
val fooOrdering: Ordering[Foo] = Ordering.by(_.b)
val ss = SortedSet(Foo(2, 2), Foo(2, 1), Foo(1, 2))(fooOrdering)
// ss: scala.collection.immutable.SortedSet[Foo] = TreeSet(Foo(2,1), Foo(1,2))
val fooOrdering: Ordering[Foo] = Ordering.by(foo => (foo.b, foo.a))
val ss = SortedSet(Foo(2, 2), Foo(2, 1), Foo(1, 2))(fooOrdering)
// ss: scala.collection.immutable.SortedSet[Foo] = TreeSet(Foo(1,2), Foo(2,1), Foo(2,2))