Лучший способ представить цикл чтения строки в Scala? - PullRequest
13 голосов
/ 13 августа 2011

Исходя из C / C ++ фона, я не очень знаком с функциональным стилем программирования, поэтому весь мой код имеет тенденцию быть очень императивным, поскольку в большинстве случаев я просто не вижу лучшего способа сделать это.

Мне просто интересно, есть ли способ сделать этот блок из Scala code more " функциональный "?

var line:String = "";
var lines:String = "";

do {
    line = reader.readLine();
    lines += line;
} while (line != null)

Ответы [ 4 ]

27 голосов
/ 13 августа 2011

Как насчет этого?

val lines = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString
13 голосов
/ 13 августа 2011

Ну, в Scala вы можете сказать:

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

Но это просто библиотека сахара. См. Прочитать весь файл в Scala? для других возможностей. На самом деле вы спрашиваете, как применить функциональную парадигму к этой проблеме. Вот подсказка:

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

У тебя есть идея? Строка foreach в файле выполняет функцию println. Кстати, не волнуйтесь, getLines() возвращает итератор, а не весь файл. Теперь что-то более серьезное:

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

Видишь идею? Возьмите lines (это может быть массив, список, набор, итератор, все, что может быть отфильтровано и содержит элементы, имеющие метод startsWith) и filter, берущие только элементы, начинающиеся с "ab". Теперь возьмите каждый предмет и map, применяя метод toUpperCase. Наконец foreach получившийся предмет print ит.

Последняя мысль: вы не ограничены одним типом. Например, скажем, у вас есть файл, содержащий целое число, по одному в строке. Если вы хотите прочитать этот файл, проанализируйте число и суммируйте их, просто скажите:

lines.map(_.toInt).sum
1 голос
/ 04 июля 2017

Чтобы добавить, как этого можно достичь, используя ранее новые nio файлы, которые я голосую за использование, потому что у него есть несколько преимуществ:

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 wont, e.g. concatenate
val result = lines.mkString
0 голосов
/ 19 августа 2011

Я считаю, что Stream - довольно хороший подход: он создает обратимую (при необходимости) последовательность:

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

Каждый элемент Stream имеет значение (в данном случае String, line) и вызывает функцию (в этом примере loadLines(in)), которая будет лениво возвращать следующий элемент по требованию. , Это обеспечивает хороший профиль использования памяти, особенно с большими наборами данных - строки не читаются до тех пор, пока они не нужны, и не сохраняются, если что-то фактически не удерживает их. Тем не менее, вы также можете вернуться к предыдущему элементу Stream и снова пройти вперед, получая точно такой же результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...