任何人都可以在Scala中优化以下语句:
// maybe large
val someArray = Array(9, 1, 6, 2, 1, 9, 4, 5, 1, 6, 5, 0, 6)
// output a sorted list which contains unique element from the array without 0
val newList=(someArray filter (_>0)).toList.distinct.sort((e1, e2) => (e1 > e2))
由于性能至关重要,有更好的方法吗?
谢谢。
答案 0 :(得分:20)
这条简单的行是迄今为止最快的代码之一:
someArray.toList.filter (_ > 0).sortWith (_ > _).distinct
但到目前为止,明显的赢家是 - 由于我的测量 - 杰德韦斯利 - 史密斯。也许如果Rex的代码是固定的,它看起来会有所不同。
典型免责声明1 + 2:
这是生成图形的基础benchcoat-code and the concrete code (gnuplot)。 Y轴:以秒为单位的时间。 X轴:阵列中的100 000到1 000 000个元素。
在发现Rex代码的问题之后,他的代码和Jed的代码一样快,但最后一个操作是将他的Array转换为List(以填满我的基准界面)。使用var result = List [Int]
和result = someArray (i) :: result
加速他的代码,使其速度大约是Jed-Code的两倍。
另一个,也许有趣的发现是:如果我按照filter / sort / distinct(fsd)=>的顺序重新排列我的代码。 (dsf,dfs,fsd,...),所有6种可能性都没有显着差异。
答案 1 :(得分:7)
我没有测量过,但是我和Duncan在一起,排序到位,然后使用类似的东西:
util.Sorting.quickSort(array)
array.foldRight(List.empty[Int]){
case (a, b) =>
if (!b.isEmpty && b(0) == a)
b
else
a :: b
}
从理论上讲,这应该非常有效。
答案 2 :(得分:4)
如果没有基准测试,我无法确定,但我认为以下内容非常有效:
val list = collection.SortedSet(someArray.filter(_>0) :_*).toList
另请尝试在您的版本中的someArray之后添加.par
。它不能保证更快,有点可能。你应该运行一个基准测试和实验。
sort
已弃用。请改用.sortWith(_ > _)
。
答案 3 :(得分:3)
拳击原语将给你10-30倍的性能惩罚。因此,如果确实性能有限,那么您将需要处理原始基本数组:
def arrayDistinctInts(someArray: Array[Int]) = {
java.util.Arrays.sort(someArray)
var overzero = 0
var ndiff = 0
var last = 0
var i = 0
while (i < someArray.length) {
if (someArray(i)<=0) overzero = i+1
else if (someArray(i)>last) {
last = someArray(i)
ndiff += 1
}
i += 1
}
val result = new Array[Int](ndiff)
var j = 0
i = overzero
last = 0
while (i < someArray.length) {
if (someArray(i) > last) {
result(j) = someArray(i)
last = someArray(i)
j += 1
}
i += 1
}
result
}
如果你小心的话,你可以稍微好一些(并且要警告,我把它打成了我的头顶;我可能已经打错了东西,但这是使用的样式),但是如果你发现了现有版本太慢,这应该至少快5倍,可能还要多。
编辑(除了修复以前的代码以使其实际有效):
如果您坚持以列表结尾,那么您可以随时构建列表。你可以递归地执行此操作,但我不认为在这种情况下它比迭代版本更清晰,所以:
def listDistinctInts(someArray: Array[Int]): List[Int] = {
if (someArray.length == 0 || someArray(someArray.length-1) <= 0) List[Int]()
else {
java.util.Arrays.sort(someArray)
var last = someArray(someArray.length-1)
var list = last :: Nil
var i = someArray.length-2
while (i >= 0) {
if (someArray(i) < last) {
last = someArray(i)
if (last <= 0) return list;
list = last :: list
}
i -= 1
}
list
}
}
另外,如果您不能通过排序来销毁原始数组,那么如果您复制数组并销毁副本(基元的数组副本非常快),那么您最好是最好的。
请记住,根据数据的性质,有一些特殊情况的解决方案要快得多。例如,如果您知道您有一个长数组,但数字将在一个较小的范围内(例如-100到100),那么您可以使用bitset来跟踪您遇到的数据。
答案 4 :(得分:2)
为了提高效率,取决于你的大值:
val a = someArray.toSet.filter(_>0).toArray
java.util.Arrays.sort(a) // quicksort, mutable data structures bad :-)
res15: Array[Int] = Array(1, 2, 4, 5, 6, 9)
请注意,这是使用未装箱数组上的qsort进行排序。
答案 5 :(得分:1)
我无法衡量,但还有一些建议......
在转换为列表之前对数组进行排序可能会更有效,并且您可能会考虑从排序列表中手动删除重复项,因为它们将组合在一起。在排序之前或之后移除0的成本也取决于它们与其他条目的比率。
答案 6 :(得分:1)
如何将所有内容添加到有序集合中?
val a = scala.collection.immutable.SortedSet(someArray filter (0 !=): _*)
当然,您应该基准代码来检查更快的内容,更重要的是,这确实是一个热点。