使用Scala编程风格的练习

时间:2015-09-24 21:50:47

标签: scala coding-style

我最近开始阅读“Exercises in programming style”一书,其中一项任务是用您选择的语言实现每种编程风格。我决定和Scala一起去(我对它很新)我已经坚持了第一个“好老派”的风格。约束是:

  
      
  • 非常少量的主存储器,通常比需要处理/生成的数据小几个数量级。 (该示例将限制设置为1024个单元格)

  •   
  • 没有标签 - 即没有变量名称或标记的内存地址。我们所拥有的只是可通过数字寻址的记忆。

  •   

原始示例(逐行读取文件并对单词进行计数)在Python中,如下所示:

data = []
data.append([])    # data[1] is line (max 80 characters)
data.append(None)  # data[2] is index of the start_char of word
data.append(0)     # data[3] is index on characters, i = 0
data.append(False) # data[4] is flag indicating if word was found
data.append('')    # data[5] is the word
data.append('')    # data[6] is word,NNNN
data.append(0)     # data[7] is frequency
...

f = open(sys.argv[1])
# Loop over input file's lines
while True:
    data[1] = [f.readline()]
...

所以我们看到有一些变量(f和数据),但主要思想是将其保持在最低限度并将python数组用作一堆“内存地址”。

甚至可以在Scala中实现老派编程风格(没有变量名称或标记的内存地址)?具体来说,有一种方法可以在读取文件内容时避免“行”变量吗?

for (line <- Source.fromFile("example.txt").getLines) {
  println(line.toUpperCase)
}

将文件内容读入类似于原始示例的数组不起作用,因为它没有提取器(值数据不是案例类,也没有unapply / unapplySeq成员)。

P.S。我非常清楚整个任务可能是Scala中的5个班轮,但这不是重点。

2 个答案:

答案 0 :(得分:0)

要获取给定文件中的总字数,可以使用以下标量代码:

Source.fromFile("example.txt")
      .getLines.map { line => line.trim.split(" ").length}
      .reduceLeft { _ + _ }

答案 1 :(得分:0)

当然,你可以避免引入除data - 数组之外的变量(并解决问题命令式)。只需将所有内容放入数组中,而不是将其分配给局部变量。

显然,代码将是一场噩梦,因为数组不会被输入,你的任何数据都没有任何有意义的名称,但我认为你的目标就是这个练习。

import scala.io.Source

/**
 * data 0 : file as line iterator
 * data 1 : index of first unused data cell
 * data 2 : current line
 * data 3 : index of the first letter of the current word
 * data 4 : index of the last letter of the current word
 * data 5 : current word
 * data 6 : temp index to find already initialized words
 * data 7 : flag: Word found
 * data 8, 10, 12, ... words
 * data 9, 11, 13, ... frequencies
 */
object GoodOldSchool {
  def main(args: Array[String]): Unit = {
    val data: Array[Any] = new Array[Any](1024)
    data(0) = Source.fromFile(args(0)).getLines()
    data(1) = 8 // first free cell
    while (data(0).asInstanceOf[Iterator[String]].hasNext) {
      data(2) = data(0).asInstanceOf[Iterator[String]].next()
      data(3) = 0 // index first letter of current word
      data(4) = 0 // index last letter of current word
      // find index last letter of current word
      while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length) {
        // find the next space (we ignore punctuation)
        while (data(4).asInstanceOf[Int] < data(2).asInstanceOf[String].length && data(2).asInstanceOf[String].charAt(data(4).asInstanceOf[Int]) != ' ') {
          data(4) = data(4).asInstanceOf[Int] + 1
        }
        data(5) = data(2).asInstanceOf[String].substring(data(3).asInstanceOf[Int], data(4).asInstanceOf[Int]) // current word
        data(6) = 8 // cell index
        data(7) = false // word already found
        8 until data(1).asInstanceOf[Int] by 2 foreach { _ =>
          // Here, we do a case-sensitive word comparison
          if (data(5) == data(data(6).asInstanceOf[Int])) {
            data(data(6).asInstanceOf[Int] + 1) = data(data(6).asInstanceOf[Int] + 1).asInstanceOf[Int] + 1 // increment frequency
            data(7) = true
          }
          data(6) = data(6).asInstanceOf[Int] + 2
        }
        if (data(7) == false) {
          // create new frequency, because word was not discovered before
          data(data(1).asInstanceOf[Int]) = data(5) // set word
          data(data(1).asInstanceOf[Int] + 1) = 1 // set frequency
          data(1) = data(1).asInstanceOf[Int] + 2 // used up two cells, update index of next free cell
        }
        // move to next word
        data(3) = data(4).asInstanceOf[Int] + 1
        data(4) = data(3)
      }
    }

    data foreach println // let's have a look at our result
  }

}