4

私はこれが別の初心者の質問だと思います。

私がやりたいのは、単語が詩に現れる頻度を数えるためにaを使用し、そのMap結果をコンソールに出力することです。私は(おそらくあまり慣用的ではないが)機能していると信じている次のコードに行きました:

val poe_m="""Once upon a midnight dreary, while I pondered weak and weary,
            |Over many a quaint and curious volume of forgotten lore,
            |While I nodded, nearly napping, suddenly there came a tapping,
            |As of some one gently rapping, rapping at my chamber door.
            |`'Tis some visitor,' I muttered, `tapping at my chamber door -
            |Only this, and nothing more.'"""

val separators=Array(' ',',','.','-','\n','\'','`')
var words=new collection.immutable.HashMap[String,Int]
for(word<-poe_m.stripMargin.split(separators) if(!word.isEmpty))  
    words=words+(word.toLowerCase -> (words.getOrElse(word.toLowerCase,0)+1))

words.foreach(entry=>println("Word : "+entry._1+" count : "+entry._2))

私が理解している限り、Scalaでは、不変のデータ構造が可変のデータ構造よりも優先され、ジレンマに直面しているのでval、結果がミュータブルに変換しながら不変に格納されると、ミュータブルを使用することを意味します。varwordsvar Mapwordsval Map

誰かがこの実存的な問題に対処する適切な方法について私に教えてもらえますか?

4

5 に答える 5

10

この場合、とを使用できgroupByますmapValues

val tokens = poe_m.stripMargin.split(separators).filterNot(_.isEmpty)
val words = tokens.groupBy(w => w).mapValues(_.size)

より一般的には、これはフォールドの仕事です。

 val words = tokens.foldLeft(Map.empty[String, Int]) {
   case (m, t) => m.updated(t, m.getOrElse(t, 0) + 1)
 }

折り目に関するウィキペディアのエントリは、いくつかの明確な例を示しています。

于 2012-04-26T14:37:30.657 に答える
2

関数型プログラミングでは、いくつかの不変オブジェクトを使用し、関数を使用してそれらを更新することが推奨されます(たとえば、更新されたマップを返す末尾再帰関数)。ただし、重い負荷を処理していない場合は、varを使用するよりも可変マップを使用することをお勧めします。これは、より強力であるためではなく(そうあるべきだと思っていても)、使いやすいためです。

最後に、Travis Brownの答えはあなたの具体的な問題の解決策であり、私のものはより個人的な哲学です。

于 2012-04-26T14:39:41.700 に答える
2

私もScalaの初心者なので、もっと良い方法があるかもしれません。私は次のことを思いついた:

poe_m.stripMargin.split(separators)
     .filter(x => !x.isEmpty)
     .groupBy(x => x).foreach {
        case(w,ws) => println(w + " " + ws.size)
     }

連続する関数を適用することで、変数や可変変数の必要性を回避できます

于 2012-04-26T14:39:55.150 に答える
1

これは、MartinOderskyによる非常に優れた本「ProgramminginScala:A Comprehensive Step-by-Step Guide、2ndEdition」で行われている方法です。

def countWords(text: String) = {
  val counts = mutable.Map.empty[String, Int]
  for (rawWord <- text.split("[ ,!.]+")) {
    val word = rawWord.toLowerCase
    val oldCount = 
      if (counts.contains(word)) counts(word)
      else 0
    counts += (word -> (oldCount + 1))
  }
  counts
}

ただし、可変マップも使用します。

于 2012-04-26T21:40:34.350 に答える
1

クレジットは他の場所(特にTravisとDaniel)にありますが、外に出る必要があるより単純な1つのライナーがありました。

val words = poe_m split "\\W+" groupBy identity mapValues {_.size}

Danielが提案したように、正規表現はマージン文字も破棄するため、stripMarginは必要ないという単純化があります。

必要に応じて、( ""-> 1)を生成する空の文字列のエッジケースから保護するために、_。isEmptyフィルタリングを保持できます。

于 2012-04-27T01:18:39.813 に答える