2013-07-01 32 views
1

這裏初始化Scala的幾個變量是代碼的一部分我從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)) 

返回結果無處以及爲val2val3

我的想法是,我必須從valCollection.map返回一個tuple並初始化所有我想要的集合。

那麼我該怎麼做?

2)由於此代碼來自Java代碼,因此在Scala世界中是否還有更高效的Collection[MyClass3]模擬?

+0

*有沒有更高效的模擬... *高效的是什麼意思? –

+0

@ om-nom-nom在任何意義上。 –

+1

這個問題跟Java沒有關係,這個標籤必須刪除。您吸引了Java專家的眼睛,他們可以明確地提供幫助,除非他們碰巧也是Scala專家,這也是Scala標籤的用處。 –

回答

3

不可變的集合

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,但你不應該這樣做一般 - 這是過早的優化的經典案例。

如果你想減少迭代次數,你可以用collect{...}(breakOut)取代filter{...}.map{...}.toMap

val val1Map: Map[String, MyClass1] = elemAndItems.collect{ 
    case (x, item) if x.key == "123" => item -> MyClass1.parse(x.value) 
    }(breakOut) 

或者你可以只filter前添加view使用延遲集合。

隨着可變集合

但是,如果你想從Java變換你的代碼的Scala你可以只使用可變集合:集合[MyClass3]

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 = { /*.....*/} 
} 

更高效的模擬

如果你想從scala代碼中調用這個構造函數,只需要使用所有的公共接口scala collectionsTraversableIterable,然後給調用者選擇實現。

+0

**使用不可變集合:** - 至少有4個循環(地圖)。有沒有辦法更有效地做到這一點? –

+0

@Grienders你可以不意味着你應該。你可以使用'foldLeft',但對於不可變的集合,你不會得到性能改進,所以你必須使用構建器。帶有構建器的解決方案與具有可變集合的解決方案几乎相同。你可以用'collect {...}(brakOut)'替換'filter {...}。map {...} toMap'或者只在'filter'前加'view'來爲每個'valNMap迭代一次'。 – senia

+0

它被轉換爲'scala.collection.immutable.Map [java.lang.String,X]'而不是'scala.collection.immutable.HashMap [java.lang.String,X]'。我該如何解決這個問題? –

1

你想要的返回類型究竟是什麼? val1val2val3?我真的不清楚你想要做什麼。我打算假設你想將valCollection分成三個HashMap s。

讓我們做一個案例類爲:

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()過程一成不變通狀態。

但是等等,這似乎是一個普遍的過程。如果斯卡拉有內置的方法來做到這一點不是很好嗎?它的確如此: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型(一個更大的問題)。

+0

'我假設你想要將valCollection分成三個HashMap。' - 我想要做的僅僅是使用不可變集合,並且不變性初始化所有4個集合:val1,val2,val3和filteredValCollection。 –

+0

我很抱歉,但我不明白你的意思。但我想另一個答案可以解決你的目標。 – pr1001