我有一个整数列表,我需要找出它所属的范围。我有一个范围列表,最大可能是2到15的范围。目前对于每个整数,我检查范围列表并找到它的位置。但是这需要花费很多时间,因为我需要检查的整数列表包括几千个。
//list of integers
val numList : List[(Int,Int)] = List((1,4),(6,20),(8,15),(9,15),(23,27),(21,25))
//list of ranges
val rangesList:List[(Int,Int)] = List((1,5),(5,10),(15,30))
def checkRegions(numPos:(Int,Int),posList:List[(Int,Int)]){
val loop = new Breaks()
loop.breakable {
for (va <- 0 until posList.length) {
if (numPos._1 >= posList(va)._1 && numPos._2 <= (posList(va)._2)) {
//i save "va"
loop.break()
}
}
}
}
目前,对于numList
中的每个整数,我都会通过rangesList
查找其范围并保存其范围位置。有没有更快/更好的方法解决这个问题?
更新:它实际上是一个与范围列表进行比较的元组列表。
答案 0 :(得分:2)
首先,在apply
上使用List
是有问题的,因为它需要线性运行时间。
List(1,2,3)(2)
必须遍历整个列表才能最终获得索引2的最后一个元素。
如果您希望代码高效,您应该找到解决方法或选择其他数据结构。像IndexedSeq
这样的数据结构具有恒定的时间索引。
你应该避免breaks
,据我所知,它可以通过例外工作,这不是一个好习惯。总有办法解决它。
您可以这样做:
val numList : List[(Int,Int)] = List((1,4),(6,20),(8,15),(9,15),(23,27),(21,25))
val rangeList:List[(Int,Int)] = List((1,5),(5,10),(15,30))
def getRegions(numList: List[(Int,Int)], rangeList:List[(Int,Int)]) = {
val indexedRangeList = rangeList.zipWithIndex
numList.map{case (a,b) => indexedRangeList
.find{case ((min, max), index) => a >= min && b <= max}.fold(-1)(_._2)}
}
并像这样使用它:
getRegions(numList, rangeList)
//yields List(0, -1, -1, -1, 2, 2)
当没有范围匹配时,我选择产生-1。关键是你事先用索引压缩范围。因此,我们知道每个范围,该范围的索引是什么,并且从不使用apply
。
如果您使用此方法让索引再次通过apply
访问rangeList中的范围,则应考虑更改为IndexedSeq
。
当数字范围变大时,apply
当然只会很昂贵。如果你提到它只有2-15,那就没问题了。我只想给你一般的想法。
答案 1 :(得分:2)
一种方法包括使用带有par
的并行集合,以及indexWhere
,它提供包含条件的集合中第一项的索引。
为了便于阅读,请考虑使用此谓词来检查区间包含,
def isIn( n: (Int,Int), r: (Int,Int) ) = (r._1 <= n._1 && n._2 <= r._2)
因此,
val indexes = numList.par.map {n => rangesList.indexWhere(r => isIn(n,r))}
indexes: ParVector(0, -1, -1, -1, 2, 2)
为每个数字提供包含它的范围集合中的索引。值-1
表示条件不成立。
要将数字与范围索引相关联,请考虑这一点,
numList zip indexes
res: List(((1,4), 0), ((6,20),-1), ((8,15),-1),
((9,15),-1), ((23,27),2), ((21,25),2))
并行集合可能比非并行集合更有效,可以对非常大量的项目执行计算。