Scala 将字符串列表转换为映射[字符串,列表]
我正在尝试将Scala 将字符串列表转换为映射[字符串,列表],scala,Scala,我正在尝试将列表(“a,1”,“b,2”,“c,3”,“a,2”,“b,4”)转换为类型scala.collection.immutable.HashMap[String,java.util.List[String],值为: a -> 1,2 b -> 2,4 c -> 3 因此,每个键都包含其值的列表 以下是我目前的代码: object ConvertList extends Application { var details = new scala.collecti
列表(“a,1”,“b,2”,“c,3”,“a,2”,“b,4”)
转换为类型scala.collection.immutable.HashMap[String,java.util.List[String]
,值为:
a -> 1,2
b -> 2,4
c -> 3
因此,每个键都包含其值的列表
以下是我目前的代码:
object ConvertList extends Application {
var details = new scala.collection.immutable.HashMap[String, java.util.List[String]]
val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
//Get all values
val getValue : Function1[String, String] = { a => a.split(",")(1) }
val allValues : List[String] = strList map getValue
//get unique values
val uniqueValues = allValues.toSet[String]
//Somehow map each unique value to a value in the original List....
println(uniqueValues)
println(strList.flatten)
//userDetails += "1" -> List("a","b",
}
如何执行此转换?列表的顺序可能不同,但通常这是一个非常可行的问题:
// for a sake of pithiness
type M = Map[String,List[String]]
def empty: M = Map.empty.withDefaultValue(Nil)
@annotation.tailrec
def group(xs: List[String], m: M = empty): M = xs match {
case Nil => m
case h::tail =>
val Array(k,v) = h.split(",")
val updated = v::m(k)
combine(tail, m + (k -> updated))
}
使用groupBy
可以直接实现这一点,因为您需要地图。groupBy
按,
拆分列表中的每个元素,并获取第一个元素,即键。因此:
scala.collection.immutable.Map[String,List[String]=Map(b->List(b,2,b,4),a->List(a,1,a,2),c->List(c,3))
。从这里开始,它只是处理从每个值列表中获取数字
这将返回一个Map[String,List[Char]]
。如果希望scala.collection.immutable.HashMap[String,java.util.List[String]]
返回,那么还有一些事情要做,但这是最简单的部分
strList.map(s => (s(0).toString,s(2).toString))
.groupBy(_._1)
.mapValues(_.map(_._2))
输出:
Map[String,List[String]] = Map(b -> List(2, 4), a -> List(1, 2), c -> List(3))
现在已经有了大量的尝试,但是类似于Marth提议的东西呢:
import scala.collection.JavaConverters._
val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
strList.map(_.split(',')).collect {
case Array(key, value) => key -> value
}.groupBy(_._1).mapValues(_.map(_._2).asJava)
这在很大程度上依赖于函数式编程,最终得到类型为Map[String,java.util.List[String]]
的Map
,而不仅仅是在输入字符串中固定位置,而是在逗号处拆分(想象数字超过9,需要多个数字)
此外,如果拆分中有多个值,则collect
方法会将它们过滤掉。从Scala 2.13
开始,我们可以使用新方法(顾名思义),它是一种一次性等效于groupBy
和map
ping分组项的方法:
// val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
strList.map(_.split(",")).groupMap(_(0))(_(1))
// Map("b" -> List(2, 4), "a" -> List(1, 2), "c" -> List(3))
这:
- 拆分每个字符串(生成
列表(数组(a,1),数组(b,2),…)
)
根据元素的第一部分((0)
)对元素进行分组(组映射的分组部分)
map
s将分组元素映射到它们的第二部分((1)
)(映射组的一部分map)
你对不可变hashmap严格吗?@om nom nom不,我只是想避免一个强制性的解决方案。你能解释一下“s(0).toString,s(2).toString”吗?它是否将每个字符串元素映射到一个字符串、字符串元组?回答得很好。在字符串上建立索引确实使这个解决方案变得干净。向上投票。是的,它将每个字符串映射到这对夫妇(“第一个字母”、“第三个字母”)。(因此,“a,1”至(“a”,“1”))。您可以(而且应该说,这段代码不仅仅是一个脑筋急转弯)编写一个函数formatString,并使用strList.map(formatString.groupBy(…)更好地处理特殊情况(string.length<3,等等)
// val strList = List("a,1" , "b,2" , "c,3" , "a,2" , "b,4")
strList.map(_.split(",")).groupMap(_(0))(_(1))
// Map("b" -> List(2, 4), "a" -> List(1, 2), "c" -> List(3))