我正在尝试通过给定输入整数以两种方式获取最接近的键值。
示例:
定义的地图如下。
$(function(){
$('#opencard').click(function(e){
e.preventDefault();
$('#deck a[href="#menu11"]').tab('show');
})
})
键是整数,它们按顺序增加。 如果说95作为输入,那么我应该得到元组输出如下 ((90->“ A”),(100->“ I”))
val m = Map(10 -> "W",20 -> "W",30 -> "I",40 -> "A",50 -> "P",60 -> "S",70 -> "A",80 -> "A",90 -> "A",100 -> "I",110 -> "A",120 -> "E")
在实际情况下(1K),地图大小会很大,我想避免使用sortBy()。有没有可能的foldLeft或地图解决方案?
答案 0 :(得分:2)
这是一种利用TreeMap
的排序和范围查询功能的方法,如下所示:
def nearestValues(m: Map[Int, String], key: Int) = {
import scala.collection.immutable.TreeMap
val tm = TreeMap(m.toSeq: _*)
Seq(tm.to(key).lastOption, tm.from(key).headOption).flatten.distinct
}
val m = Map(
10 -> "W", 20 -> "W", 30 -> "I", 40 -> "A", 50 -> "P", 60 -> "S",
70 -> "A", 80 -> "A", 90 -> "A", 100 -> "I", 110 -> "A", 120 -> "E"
)
nearestValues(m, 95)
// res1: Seq[(Int, String)] = List((90,A), (100,I))
nearestValues(m, 20)
// res2: Seq[(Int, String)] = List((20,W))
nearestValues(m, 125)
// res3: Seq[(Int, String)] = List((120,E))
请注意,上述方法返回Seq
而不是Tuple
来容纳完全匹配或单面匹配的情况。要返回Tuple
,可以使用类似于以下内容的东西:
def nearestValues(m: Map[Int, String], key: Int) = {
import scala.collection.immutable.TreeMap
val tm = TreeMap(m.toSeq: _*)
Seq(tm.to(key).lastOption, tm.from(key).headOption) match {
case Seq(None, None) => (0 -> "", 0 -> "") // Default tuple for empty Map
case Seq(x, None) => (x.get, Int.MaxValue -> "")
case Seq(None, y) => (Int.MinValue -> "", y.get)
case Seq(x, y) => (x.get, y.get)
}
}
nearestValues(m, 95)
// res1: ((Int, String), (Int, String)) = ((90,A),(100,I))
nearestValues(m, 20)
// res2: ((Int, String), (Int, String)) = ((20,W),(20,W))
nearestValues(m, 125)
// res3: ((Int, String), (Int, String)) = ((120,E),(2147483647,""))
答案 1 :(得分:2)
这是一个非常简单的解决方案。无需排序。
def nearest[V](m :Map[Int,V], k :Int) :Seq[(Int,V)] =
m.get(k).fold {
val (before, after) = m.keys.partition(_ < k)
Seq(before.maxOption, after.minOption).flatten.map(x => (x,m(x)))
}(v => Seq((k,v)))
测试:
val m = Map(10 -> "W",20 -> "W",30 -> "I",40 -> "A",50 -> "P",60 -> "S",70 -> "A",80 -> "A",90 -> "A",100 -> "I",110 -> "A",120 -> "E")
nearest(m, -7) //res0: Seq[(Int, String)] = List((10,W))
nearest(m, 60) //res1: Seq[(Int, String)] = List((60,S))
nearest(m, 93) //res2: Seq[(Int, String)] = List((90,A), (100,I))
nearest(m, 121) //res3: Seq[(Int, String)] = List((120,E))
答案 2 :(得分:1)
您可以按照Leo C的建议使用排序的集合,但是这需要先构造集合然后进行搜索,所以这种算法的复杂度将为O(n*log n)
。
以算法方式处理此任务,您可以计算键的差,然后找到最接近的负值和正值至0。在这种情况下,复杂度会降低O(n)
。
下面的示例从左侧和右侧返回最接近的键,不包括精确匹配项(您可以通过更改过滤器中的条件来更改该键):
val data = Map(1-> "a", 5->"b")
val key = 4
val diffs = data.keys.map(_ - key)
val rightKeyOpt = diffs.filter(_ > 0).reduceOption(_ min _).map(_ + key)
val leftKeyOpt = diffs.filter(_ < 0).reduceOption(_ max _).map(_ + key)
val result = (leftKeyOpt.map(k=> k->data(k)), rightKeyOpt.map(k=> k->data(k)))
println (leftKeyOpt, rightKeyOpt)
println result
我敢打赌,如果您需要的话,可以在一行中完成:)