【问题标题】:Fastest way to check list of integers against a list of Ranges in scala?根据scala中的范围列表检查整数列表的最快方法?
【发布时间】:2014-08-20 16:30:56
【问题描述】:

我有一个整数列表,我需要找出它所在的范围。我有一个范围列表,它的大小可能最大为 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 查找其范围并保存其范围位置。有没有更快/更好的方法来解决这个问题?

更新:它实际上是与范围列表进行比较的元组列表。

【问题讨论】:

  • 给我们看一些代码 :) 你试过 .par 吗?
  • 你到底是什么意思:“需要找出它属于哪个范围”。您是否将每个Int 映射到Range?您的预期结果如何?
  • 我已经更新了这个问题。我有一个元组列表(Tuples2),我将其与范围列表进行比较,并将每个 Tuple2 映射到列表中的一个范围。我将范围的位置保存在列表中。
  • 所以我猜List[Position] 应该是范围。那么为什么rangesList(Int,Int) 类型呢?你先把它们映射到Positions
  • 我使用 Positions 对象,但是对于这里的示例,我想将它作为 tuple2 给出,我已经更正了示例。

标签: list scala intervals scala-collections


【解决方案1】:

首先,在List 上使用apply 是有问题的,因为它需要线性运行时间。

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,那没问题。我只是想给你一个大概的想法。

【讨论】:

    【解决方案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))
    

    在对大量项目执行计算方面,并行集合可能比非并行集合更有效。

    【讨论】:

      猜你喜欢
      • 2011-11-04
      • 2012-08-05
      • 1970-01-01
      • 2021-12-16
      • 2016-09-27
      • 2011-11-08
      • 2018-11-03
      • 1970-01-01
      • 2021-05-23
      相关资源
      最近更新 更多