以下是我从Java转换的代码的一部分
class Regex(valCollection: Collection[MyClass3]) {
private val val1 = new HashMap[String, MyClass1]
private val val2 = new HashMap[String, String]
private val val3 = new HashMap[String, MyClass2]
private val filteredValCollection = valCollection.map(x => {
val valCollectionItem = getValCollectionItem(x)
x.key match {
case "123" => val1 + (valCollectionItem -> MyClass1.parse(x.value)) //TODO -- append to val1
case "456" => val2 + (valCollectionItem -> x.value) //TODO -- append to val2
case "789" => val3 + (valCollectionItem -> MyClass2.parse(x.value)) //TODO -- append to val3
}
valCollectionItem
})
def getValCollectionItem = { /*.....*/}
}
1)我想要做的只是使用不可变集合和不变性初始化所有4个集合:val1, val2, val3 and filteredValCollection
。正如您所看到的,filteredValCollection
已初始化,并且没有问题。但是,
case "123" => val1 + (valCollectionItem -> MyClass1.parse(x.value))
将结果返回到val2
和val3
。
我的想法是,我必须从tuple
返回valCollection.map
并初始化我想要的所有收藏品。
那我该怎么做?
2)由于此代码来自Java代码,Scala世界中是否有更高效的Collection[MyClass3]
模拟?
答案 0 :(得分:2)
使用不可变的集合
def parseValCollection = {
val elemAndItems = valCollection.map{ x => x -> getValCollectionItem(x) }
val valCollectionItems = elemAndItems.map{ case (_, item) -> item }
val val1Map = elemAndItems.filter{ case (x, _) => x.key == "123" }.
map{ case (x, item) => item -> MyClass1.parse(x.value) }.toMap
val val2Map = elemAndItems.filter{ case (x, _) => x.key == "456" }.
map{ case (x, item) => item -> x.value }.toMap
val val3Map = elemAndItems.filter{ case (x, _) => x.key == "789" }.
map{ case (x, item) => item -> MyClass2.parse(x.value) }.toMap
(valCollectionItems, val1Map, val2Map, val3Map)
}
private val (valCollectionItems, val1Map, val2Map, val3Map) = parseValCollection
如果您只想在使用valCollection
后迭代foldLeft
,但您不应该正常进行 - 这是过早优化的经典案例。
如果您想减少迭代次数,可以将filter{...}.map{...}.toMap
替换为collect{...}(breakOut)
:
val val1Map: Map[String, MyClass1] = elemAndItems.collect{
case (x, item) if x.key == "123" => item -> MyClass1.parse(x.value)
}(breakOut)
或者,您可以在view
之前添加filter
以使用延迟收藏。
使用可变集合
但是如果你想将代码从java转换为scala,你可以使用可变集合:
import collection.{mutable => m}
class Regex(valCollection: Iterable[MyClass3]) {
private val val1 = m.Map[String, MyClass1]()
private val val2 = m.Map[String, String]()
private val val3 = m.Map[String, MyClass2]()
private val filteredValCollection = m.Seq[ItemType]()
for( x <- valCollection){
val valCollectionItem = getValCollectionItem(x)
filteredValCollection += valCollectionItem
x.key match {
case "123" => val1 += (valCollectionItem -> MyClass1.parse(x.value))
case "456" => val2 += (valCollectionItem -> x.value)
case "789" => val3 += (valCollectionItem -> MyClass2.parse(x.value))
}
}
def getValCollectionItem: ItemType = { /*.....*/}
}
更高效的Collection [MyClass3]模拟
如果你想从scala代码调用这个构造函数,你应该使用所有scala collections:Traversable
或Iterable
的公共接口,并给调用者留下实现的选择。
答案 1 :(得分:0)
您想要的返回类型到底是什么? val1
,val2
,val3
?我真的不清楚你要做什么。我假设您要将valCollection
分为三个HashMap
。
让我们为此制作一个案例类:
case class CollectionResult(
val val1: HashMap[String, MyClass1],
val val2: HashMap[String, String],
val val3: HashMap[String, MyClass2]
)
如果所有3个结果都具有相同的类型,则可以使用简单的Tuple3
...
但是让我们使用CollectionResult
。您现在需要一个带Collection[MyClass3]
并返回CollectionResult
:
def partition(input: Collection[MyClass3]): CollectionResult
顾名思义,我们会经历input
,在我们去的时候对值进行分区。由于我们需要一个CollectionResult
,其中很多,我们将使用foldLeft
:
def partition(input: Collection[MyClass3]): CollectionResult = {
val initialAccumulator = CollectionResult(HashMap.empty, HashMap.empty, HashMap.empty, Collection.empty)
input.foldLeft(initialAccumulator)((accumulator, inputVal) => {
val newVal1 = (if (inputVal.x == "123") accumulator.val1 + (inputVal -> MyClass1.parse(inputVal.value)) else accumulator.val1)
val newVal2 = (if (inputVal.x == "456") accumulator.val2 + inputVal.value else accumulator.val2)
val newVal3 = (if (inputVal.x == "789") accumulator.val3 + (inputVal -> MyClass2.parse(inputVal.value)) else accumulator.val3)
CollectionResult(newVal1, newVal2, newVal3)
})
}
正如您所看到的,CollectionResult
的实例用于通过foldLeft()
进程不可避免地传递状态。
但等等,这似乎是一个普遍的过程。如果Scala有一个内置的方法来做这件事会不会很好?它确实:groupBy()
。它只需要一个带入值的函数,并返回结果Map
的键。
让我们用它:
val partitioned: Map[String, Class3] = valCollection.groupBy(inputVal => inputVal.x)
val transformed: Map[String, Any] = partitioned.map((keyValue) => {
val (key, value) = keyValue
key match {
case "123" => MyClass1.parse(value)
case "789" => MyClass2.parse(value)
case _ => value
}
})
这非常简洁,但它的缺点是需要多次迭代(可能不是真正的问题)并且必须使用Any
类型(更大的问题)。