Best way to represent a readline loop in Scala?

后端 未结 4 1154
悲哀的现实
悲哀的现实 2021-01-08 00:41

Coming from a C/C++ background, I\'m not very familiar with the functional style of programming so all my code tends to be very imperative, as in most cases I just can\'t se

相关标签:
4条回答
  • 2021-01-08 01:06

    To add how the same can be achieved using the formerly new nio files which I vote to use because it has several advantages:

    val path: Path = Paths.get("foo.txt")
    val lines = Source.fromInputStream(Files.newInputStream(path)).getLines()
    
    // Now we can iterate the file or do anything we want,
    // e.g. using functional operations such as map. Or simply concatenate.
    val result = lines.mkString
    

    Don't forget to close the stream afterwards.

    0 讨论(0)
  • 2021-01-08 01:13

    Well, in Scala you can actually say:

    val lines = scala.io.Source.fromFile("file.txt").mkString
    

    But this is just a library sugar. See Read entire file in Scala? for other possiblities. What you are actually asking is how to apply functional paradigm to this problem. Here is a hint:

    Source.fromFile("file.txt").getLines().foreach {println}
    

    Do you get the idea behind this? foreach line in the file execute println function. BTW don't worry, getLines() returns an iterator, not the whole file. Now something more serious:

    lines filter {_.startsWith("ab")} map {_.toUpperCase} foreach {println}
    

    See the idea? Take lines (it can be an array, list, set, iterator, whatever that can be filtered and which contains an items having startsWith method) and filter taking only the items starting with "ab". Now take every item and map it by applying toUpperCase method. Finally foreach resulting item print it.

    The last thought: you are not limited to a single type. For instance say you have a file containing integer number, one per line. If you want to read that file, parse the number and sum them up, simply say:

    lines.map(_.toInt).sum
    
    0 讨论(0)
  • 2021-01-08 01:16

    I find that Stream is a pretty nice approach: it create a re-traversible (if needed) sequence:

    def loadLines(in: java.io.BufferedReader): Stream[String] = {
      val line = in.readLine
      if (line == null) Stream.Empty
      else Stream.cons(line, loadLines(in))
    }
    

    Each Stream element has a value (a String, line, in this case), and calls a function (loadLines(in), in this example) which will yield the next element, lazily, on demand. This makes for a good memory usage profile, especially with large data sets -- lines aren't read until they're needed, and aren't retained unless something is actually still holding onto them. Yet you can also go back to a previous Stream element and traverse forward again, yielding the exact same result.

    0 讨论(0)
  • 2021-01-08 01:30

    How about this?

    val lines = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString
    
    0 讨论(0)
提交回复
热议问题