因此,我有一个ArrayBuffer [Signal],其中每个Signal都有一个时间戳(该数组按该时间戳排序)。我想进行二进制搜索并返回一定范围内的信号的Seq [Signal]。现在,它是通过线性搜索完成的,基本上是因为我来自Java,并且是Scala的新手。哪种方法最好?
代码如下:
/userinfo
答案 0 :(得分:0)
您可以使用“搜索”进行二进制搜索。
import scala.collection.Searching._
val signalWithLowerBoundTimestamp = ???
val signalWithUpperBoundTimestamp = ???
val lower = signals.search(signalWithLowerBoundTimestamp)(
Ordering.by(_.timestamp)).insertionPoint
// If the upper bound is an exact match, add one
// to make sure it's included in the slice.
val upper = signals.search(signalWithUpperBoundTimestamp)(
Ordering.by(_.timestamp)) match {
case Found(i) => i + 1
case InsertionPoint(i) => i
}
val result = signals.slice(lower, upper)
答案 1 :(得分:0)
您可以使用dropWhile
和takeWhile
。
这样,您可以保存所有可变性和迭代。
注意:,它仍然是线性的,但在 Scala 中,它更具功能且更常见。
private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] =
getCache(VehicleWithMap(mapId, mac)
.dropWhile(_.timestamp < startTime)
.takeWhile(_.timestamp <= endTime)
}
(请务必先进行测试,您可能需要对条件有所了解)。
答案 2 :(得分:0)
我不知道scala,但是这是一个二进制搜索,您可以将其与更多功能样式的答案进行比较。我认为其中没有任何可耻之处。请注意,对结束索引进行二进制搜索没有任何好处,因为无论如何您都必须复制元素:
private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] = {
val signals = getCache(VehicleWithMap(mapId, mac))
var startIndex: Int = 0
var endIndex: Int = signals.size
while(startIndex<endIndex) {
var testIndex: int = startIndex + (endIndex-startIndex)/2
if (signals(testIndex).timestamp < startTime) {
startIndex = testIndex + 1
} else {
endIndex = testIndex
}
}
while(endIndex < signals.size && signals(endIndex).timestamp <= endTime) {
endIndex = endIndex + 1
}
signals.slice(startIndex, endIndex)
}
请注意,我在信号timestamp == endTime
的末尾添加了信号,因为那是您所做的……但是这会使界面有些奇怪。通常,这样的方法将被编写为使用startTime <= timeStamp < endTime
返回信号,所以也许您想考虑更改它。