我希望最有效地按第三个值排序ListBuffer(Int, Int, Int)
。这就是我现在拥有的。我正在使用sortBy
。注意y
和z
都是ListBuffer[(Int, Int, Int)]
,我首先要解决这个问题。我的目标是优化它并最有效地执行此操作(取两个列表之间的差异并按第三个元素排序)。我假设diff
部分无法优化,但sortBy可以,所以我正在寻找一种有效的方法来做排序部分。我找到了关于排序数组的帖子,但我正在使用ListBuffer并转换为数组会增加开销,所以我宁愿不转换我的ListBuffer。
val x = (y diff z).sortBy(i => i._3)
答案 0 :(得分:5)
1)如果您想使用Scala库,那么您无法做得更好。 Scala已经尝试以最有效的方式对您的集合进行排序。
SeqLike
定义调用此实现的def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr = sorted(ord on f)
:
def sorted[B >: A](implicit ord: Ordering[B]): Repr = {
val len = this.length
val arr = new ArraySeq[A](len)
var i = 0
for (x <- this.seq) {
arr(i) = x
i += 1
}
java.util.Arrays.sort(arr.array, ord.asInstanceOf[Ordering[Object]])
val b = newBuilder
b.sizeHint(len)
for (x <- arr) b += x
b.result
}
这是您的代码将调用的内容。如您所见,它已经使用数组来对数据进行排序。根据{{1}}的{{3}}:
实施说明:此实施是稳定的,适应性的, 迭代合并,需要远远少于n lg(n)的比较 当输入数组部分排序时,同时提供 输入数组时传统mergesort的性能 随机排序。如果输入数组几乎排序,那么 实施需要大约n次比较。
2)如果您尝试通过将diff的结果直接插入排序结构(如二叉树)进行优化,因为您逐个元素生成它们,您仍将支付相同的价格:平均插入费用为public static void sort(Object[] a)
次log(n)
个元素n
- 与合并排序等快速排序算法相同。
3)因此,除非您针对特定用例进行优化,否则无法对此案例进行优化。
3a)例如,= n log(n)
可能会替换为ListBuffer
而Set
应该更快。事实上,它实现为:
diff
使用的 def diff(that: GenSet[A]): This = this -- that
反过来应该比-
上的diff
更快,而Seq
必须首先构建地图:
def diff[B >: A](that: GenSeq[B]): Repr = {
val occ = occCounts(that.seq)
val b = newBuilder
for (x <- this)
if (occ(x) == 0) b += x
else occ(x) -= 1
b.result
}
3b)您还可以使用_3
作为数组中的索引来避免排序。如果使用该索引插入,则将对数组进行排序。这仅在您的数据足够密集或者您很乐意随后处理稀疏数组时才有效。一个索引也可能有多个值映射到它,你也必须处理它。实际上,您正在构建有序地图。您也可以使用Map
,但HashMap
不会被排序,TreeMap
将需要log(n)
再次添加操作。
咨询javadoc,了解根据您的情况可以获得的收益。
4)无论如何,在现代计算机上排序真的很快。做一些基准测试,以确保您不会过早地优化它。
总结不同情景的复杂性......
您目前的情况:
SeqLike
:n
从that
+ n
创建地图以迭代this
(地图查找实际上是恒定时间(C) )= 2n
或O(n)
O(n log(n))
O(n) + O(n log(n))
= O(n log(n))
,更确切地说:2n + nlog(n)
如果您使用Set
代替SeqLike
:
Set
:n
要迭代(查询为C)= O(n)
O(n) + O(n log(n))
= O(n log(n))
,更确切地说:n + nlog(n)
如果使用Set
和数组插入:
O(n) + O(0)
= O(n)
,更确切地说:n
。对于稀疏数据可能不太实用。在宏观方案中看起来并不重要,除非你有一个独特的案例,从最后一个选项(数组)中受益。
如果你有ListBuffer[Int]
而不是ListBuffer[(Int, Int, Int)]
我会建议先对两个集合进行排序,然后通过同时对它们进行单次传递来做差异。这将是O(nlog(n))
。在您的情况下,_3
排序不足以保证两个集合中的确切顺序。您可以按元组的所有三个字段进行排序,但这会改变原始顺序。如果您对此感到满意并编写自己的差异,那么它可能是最快的选择。