Scala HashMap抛出键未找到异常

时间:2014-03-09 21:11:05

标签: java scala iterator hashmap key

我对Scala很新,并且会感谢任何帮助(已经到处寻找,并且花了最后8个小时试图解决这个问题)

目前我有

def apply(file: String) : Iterator[String] =  {
    scala.io.Source.fromFile(file).getLines().map(_.toLowerCase)
    }

以及

def groupFreq[A,B](xs: Iterator[A], f: A => B): HashMap[B, Int] = { 
    var freqMap = new HashMap[B, Int]
    for (x <- xs) freqMap = freqMap + ( f(x) -> ( freqMap.getOrElse( f(x) , 0 ) +1 )  )  
    freqMap
  }

apply只需要传入我们传入的文字文件。

GroupFreq采用xs:Iterator [A]和一个将A值转换为B组的分组函数f。 该函数返回一个HashMap,它为每个B组计算落入该组的A值的数量。

我使用这两个函数来帮助我使用charFreq,这个函数同时使用apply和groupFreq传回一个HashMap,它计算Char在整个文件中出现的次数。如果char没有出现在文件中的任何位置,那么就不应该有它的映射。

def charFreq(file: String): HashMap[Char, Int] = 
  {
    var it = Iterator[Char]()
    val words = apply(file)
    for {
        xs<-words
    } yield { it = it ++ xs.toIterator }

    val chars   = it
    val grouper = (x: Char) => x
    groupFreq(chars, grouper) 
  }

我的解决方案编译并应用和groupFreq按预期工作,但是当我运行charFreq时,它说

  

charFreq抛出异常:java.util.NoSuchElementException:key not   发现:d

我相信我做错了什么,最有可能是我的for循环和收益,但我已经多次完成逻辑,我不明白为什么它不起作用。

谷歌和StackOverflow推荐使用平面地图,但是我也不能这样做。

任何帮助将不胜感激。请记住,这是一个设置了骨架方法的类赋值,因此我无法更改apply和groupFreq和charFreq的设置方式,我只能操作我试过的实体。

2 个答案:

答案 0 :(得分:1)

我无法使用字符串的随机文本文件重现您的错误。我怀疑它发生在groupFreq() w {o getOrElse()类型测试的早期迭代中。

但是,在运行代码时,我最终会在调用charFreq()时显示一张空地图。您已经纠正了charFreq()中的循环/收益是有问题的。将val l =放在for前面并查看IDE中l类型为Iterator[Unit]的值时,会更容易看到。

vars循环不需要forfor循环与C风格的循环不同,相当于在其元素上调用flatMap / map(尽管其他人可以比我更好地表达)。产量被连接到你的东西(由你在其中采取的步骤定义)。

以下两种方法可以Iterator[Char]拨打groupFreq()

1&GT;删除不必要的var it并使用for comprehension循环直接填充chars

val chars = for {
    xs<-words
    i<-xs.toIterator
} yield { i }

2 - ;直接在flatMap val:

上致电words
val chars = words.flatMap( s => s )

答案 1 :(得分:1)

一个。关于你的问题,我可以在代码中看到至少一个问题:

构建迭代器(在charFreq中)的方式似乎太重了。 words.toIterator就足够了。

你更新地图的方式对我来说也很奇怪。我宁愿这样做:

val mapped = f(x)
if (!(freqMap contains mapped) freqMap(mapped) = 0
freqMap(mapped)+=1   

B中。据我所知,这个问题可以通过单行解决(这就是为什么Scala当然很酷;-))

def charFreq(file:String) = 
    file.toCharArray.groupBy(m=>m).map(m => (m._1,m._2.size))

说明:

1)toCharArray将您的字符串转换为Char元素数组

2)groupBy(m =&gt; m)将具有相同值的所有元素组合在一起,结果将为Map[Char,Array[Char]]类型,其中每个char都映射到您的所有char中出现的数组字符串。

3)现在我们只需要使用映射Map[Char,Array[Char]]Map[Char,Int]]的每个条目映射到map(m => (m._1,m._2.size)),映射{(1}},每个元素(key-&gt; value),离开密钥保持不变并将值(数组)转换为该数组的大小。

4)如果你的输入字符串非常大(我没有评估过它,但如果它在MB的大概中我开始担心那个),那么我可能会使用另一个解决方案,可变迭代源代码时我填写的地图:

def charFreq(hugeFile:String) = {
    //create a mutable map, which can be updated when needed
    val mm = scala.collection.mutable.Map[Char,Int]()
    //iterate over the string
    for (m <- hugeFile) { 
        //ensure that our map contains the entry for the given character
        if (! (mm contains m)) mm(m) = 0          
        mm(m) = mm(m)+1 
    }
    //return the result as an immutable map
    mm.toMap
}