我对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的设置方式,我只能操作我试过的实体。
答案 0 :(得分:1)
我无法使用字符串的随机文本文件重现您的错误。我怀疑它发生在groupFreq()
w {o getOrElse()
类型测试的早期迭代中。
但是,在运行代码时,我最终会在调用charFreq()
时显示一张空地图。您已经纠正了charFreq()中的循环/收益是有问题的。将val l =
放在for
前面并查看IDE中l
类型为Iterator[Unit]
的值时,会更容易看到。
vars
循环不需要for
。 for
循环与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
}