例如,我有Map[Integer,String]
喜欢
val map = Map(1 -> "a", 2 -> "b", 3 -> "c", 5 -> "d", 9 -> "e", 100 -> "z")
如果给定的密钥为2,则预计“b”将返回。
如果给定的密钥为50,则预期“e”和“z”将返回。
如果给定键为0,则预期“a”将返回。
换句话说,如果密钥存在于Map
中,则应返回相应的值。否则,应返回最接近的较小和较大键的值(在没有其他键较小的情况下,只应返回最近的较大键的值,反之亦然)。
如何实现这一目标?
答案 0 :(得分:6)
Map
没有保留顺序,因此我建议创建一个方法:
Map
转换为TreeMap
to(key).lastOption
和from(key).headOption
在列表中生成下/上地图条目作为选项示例代码如下:
val map = Map(1->"a", 2->"b", 100->"z", 9->"e", 3->"c", 5->"d")
def closestValues(m: Map[Int, String], key: Int): Seq[String] = {
import scala.collection.immutable.TreeMap
val tm = TreeMap(m.toSeq: _*)
Seq( tm.to(key).lastOption, tm.from(key).headOption ).
flatten.distinct.map{ case (k, v) => v }
}
closestValues(map, 0)
// res1: Seq[String] = List(a)
closestValues(map, 2)
// res2: Seq[String] = List(b)
closestValues(map, 50)
// res3: Seq[String] = List(e, z)
closestValues(map, 101)
// res4: Seq[String] = List(z)
答案 1 :(得分:2)
我的2美分价值。
def getClose[K](m: Map[Int,K], k: Int): Seq[K] =
if (m.get(k).nonEmpty) Seq(m(k))
else {
val (below,above) = m.keys.partition(_ < k)
Seq( if (below.isEmpty) None else Some(below.max)
, if (above.isEmpty) None else Some(above.min)
).flatten.map(m)
}
答案 2 :(得分:1)
这不是一个有效的解决方案,但你可以做类似下面的事情
val map =Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val keyset = map.keySet
def getNearestValues(key: Int) : Array[String] = {
if(keyset.contains(key)) Array(map(key))
else{
var array = Array.empty[String]
val less = keyset.filter(_ < key)
if(!less.isEmpty) array = array ++ Array(map(less.toList.sortWith(_ < _).last))
val greater = keyset.filter(_ > key)
if(!greater.isEmpty) array = array ++ Array(map(greater.toList.sortWith(_ < _).head))
array
}
}
一点功能方式
val map =Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val keyset = map.keySet
def getNearestValues(key: Int) : Array[String] = keyset.contains(key) match {
case true => Array(map(key))
case false => {
val (lower, upper) = keyset.toList.sortWith(_ < _).span(x => x < key)
val lowArray = if(lower.isEmpty) Array.empty[String] else Array(map(lower.last))
val upperArray = if(upper.isEmpty) Array.empty[String] else Array(map(upper.head))
lowArray ++ upperArray
}
}
getNearestValues(0)
应该返回Array(a)
而getNearestValues(50)
应该返回Array(e, z)
而getNearestValues(9)
应该返回Array(e)
答案 3 :(得分:1)
我建议先将Map
转换为SortedMap
,因为需要考虑密钥的顺序。
val map = Map(1->"a",2->"b",3->"c",5->"d",9->"e",100->"z")
val sortedMap = SortedMap[Int, String]() ++ map
之后,使用以下方法获取最接近的值。结果以List的形式返回。
def getClosestValue(num: Int) = {
if (sortedMap.contains(num)) {
List(sortedMap(num))
} else {
lazy val larger = sortedMap.filterKeys(_ > num)
lazy val lower = sortedMap.filterKeys(_ < num)
if (larger.isEmpty) {
List(sortedMap.last._2)
} else if (lower.isEmpty) {
List(sortedMap.head._2)
} else {
List(lower.last._2, larger.head._2)
}
}
}
使用以下值对其进行测试:
println(getClosestValue(2))
println(getClosestValue(50))
println(getClosestValue(0))
println(getClosestValue(101))
将给出
List(b)
List(z, e)
List(a)
List(z)
答案 4 :(得分:0)
您可以用比上面任何建议的解决方案都小的复杂度来解决此问题。因此,如果性能至关重要,请检查this answer。
答案 5 :(得分:0)
另一个Scala解决方案
val m = Map(1 -> "a", 2 -> "b", 3 -> "c", 5 -> "d", 9 -> "e", 100 -> "z")
List(0, 2, 50, 101).foreach { i => {
val inp = i
val (mn, mx) = if (m.get(inp).nonEmpty) (Map(inp -> m(inp)), Map(inp -> m(inp))) else m.partition(x => x._1 > inp)
(mn, mx) match {
case (x, y) if y.isEmpty => println(m(mn.keys.min))
case (x, y) if x.isEmpty => println(m(mx.keys.max))
case (x, y) if y == x => println(m(inp))
case (x, y) => println(m(mn.keys.min), m(mx.keys.max))
}
}
}
结果:
a
b
(z,e)
z