2016-05-08 106 views
1

我搜索一種方法來計算字符串中的不同字符。 問題是,這是不允許使用scala-api的任何函數或使用變量(僅val)。使用scala字符串計算char字符頻率

我想這樣的

val fruit: String = "dasisteintest" 
println(fruit.groupBy(identity).mapValues(_.size)) 
Map(e -> 2, s -> 3, n -> 1, t -> 3, a -> 1, i -> 2, d -> 1) 

在每一個相同的結果,嘗試我做了,我在最後一個list[(Char,Int)],我必須改變詮釋。但是因爲這是一個不可變的列表,所以我不能改變它。 我該如何實現這個計數字符算法?

+0

並不清楚你的實際問題是什麼返回字符的功能。假設你不只是在某人回答你的任務後,你卡在哪裏?輸出應該是什麼樣子? 'Map'(和'groupBy')是scala-api的一部分,所以目前還不清楚你想要什麼。你可以用什麼? –

+0

正如我在上面寫的,我需要像** fruit.groupBy(identity).mapValues(_。size)**一樣的結果**,但沒有來自scala-api **的函數**。我所有的嘗試都失敗了,因爲每次我需要更改List的一個元素。我知道我「只」必須使用更改後的元素創建新的列表。但我不知道如何通過更改元素來實現它。所以我希望有人能夠幫助我更改List的元素(不包括api中的函數),或者有人用另一種方式來計算字符串中不同的字符......現在希望每件事都清楚嗎? – theoretisch

回答

0

這是預期的代碼。 首先從列表

def removeFromList(l: List[Char], l2: List[Char], toDelete: Char): List[Char] = { 
     if (l.isEmpty) l2 
     else { 
      if (l.head == toDelete) 
       removeFromList(l.tail, l2, toDelete) 
      else 
       removeFromList(l.tail, l2 :+ l.head, toDelete) 
     } 
    } 

然後函數計算的字符,並呼籲removeFromList()

def zaehlZeichen(s: String): List[(Char, Int)] = { 
    val sl: List[Char] = s.toUpperCase().toList 
    if (sl.isEmpty) Nil 
    else { 
     val l: List[Char] = List() 
     val tupleList: List[(Char, Int)] = List(); 
     val in: Int = countChar(sl, 0, sl.head) 
     val t: List[(Char, Int)] = tupleList :+ (sl.head, in) 
     val cutL: List[Char] = removeFromList(sl, l, sl.head) 
     t ::: zaehlZeichen(cutL.mkString); 
    } 
    } 
1

您可以使用下面的代碼片段:

val fruit: String = "dasisteintest" 
val map = scala.collection.mutable.HashMap.empty[Char, Int] 
for (symbol <- fruit) { 
    if (map.contains(symbol)) 
    map(symbol) = map(symbol) + 1 
    else 
    map.+=((symbol, 1)) 
} 
println(map) 
+0

呃很酷,謝謝!我認爲,自己寫包含方法並不困難。我會馬上嘗試。 – theoretisch

+0

我的猜測是答案不應該使用可變集合,但只有OP知道肯定。 –

+0

@問題的倒數第二句話的原型保羅可以推斷該集合應該被改變。 – Aliaxander

0

你是什麼意思 「從Scala的API函數沒有」 是什麼意思?這是否包含集合api中的任何函數?如果是這樣,那麼忽略我的答案。但是,如果我們甚至不能使用reduce方法,那麼我就不會看到這個練習的重點。

這就是我想出了:

val fruit: String = "dasisteintest" 
fruit.foldLeft[Map[Char,Int]](Map.empty)((map, c) => map + (c -> (map.getOrElse(c, 0) + 1))) 

雖然可以擴大你的意思是什麼 「」 你必須改變內部「

+0

謝謝,但.foldLeft和.getOrElse是scala api的函數,不是嗎?如果我想像你一樣意識到,我必須自己編寫這些函數...... – theoretisch

+0

Scala API的作業定義是什麼 –

+0

定義只是「不使用scala-api的函數」.. 你認爲功能之間有任何區別? – theoretisch

1
def countChars(str: String) = { 
    def loop(chars: List[Char], acc: Map[Char, Int]): Map[Char, Int] = { 
    chars match { 
     case Nil => acc 
     case char :: rest => 
     loop(rest, acc + (char -> (acc(char) + 1))) 
    } 
    } 

    loop(str.toList, Map.empty[Char, Int] withDefaultValue 0) 
} 

測試:

@ val fruit: String = "dasisteintest" 
fruit: String = "dasisteintest" 
@ countChars(fruit) 
res4: Map[Char, Int] = Map('e' -> 2, 's' -> 3, 'n' -> 1, 't' -> 3, 'a' -> 1, 'i' -> 2, 'd' -> 1) 

無論你在這裏使用的是從scala api,Map.applyMap.emptyList.::。不會使用scala api中的任何函數。我的猜測是,你不應該使用像groupBy這樣的東西,你應該做一些更低層次的事情。摺疊是自然的解決方案,如foldLeft,但如果這被認爲是「使用scala api的函數」,那麼您可以自己實現foldLeft,就像我在解決方案中那樣。

至於withDefaultValue你可以用明確的檢查來替換它,如果存在值並且在那種情況下放置1。

你不知道如何改變列表或地圖是不可變的嗎?您只需更改該值即可創建新列表。

對於地圖,給

val map = Map('a' -> 3) 

可以更新它做

@ map.updated('a', 4) 
res6: Map[Char, Int] = Map('a' -> 4) 

@ map + ('a' -> 4) 
res7: Map[Char, Int] = Map('a' -> 4) 

都這樣做完全同樣的事情 - 插入或更新 - 並返回新地圖。

在這裏你可以找到如何在列表更新元素

Replace element in List with scala

雖然你很少想通過索引來訪問列表,而只是建立從舊的一個新的列表,同時遍歷它以某種方式,例如與摺疊。

+0

謝謝,與比賽的解決方案很酷。這解決了我的List完美的問題。 – theoretisch