Краткий способ чтения данных из файла в неизменяемый 2-мерный массив в Scala - PullRequest
0 голосов
/ 17 февраля 2011

То, что я ищу, - это краткий способ получить неизменный двумерный массив X и одномерный массив Y без предварительного сканирования файла, чтобы определить размерыданные.

Данные, состоящие из строки заголовка, за которой следуют столбчатые двойные значения, имеют следующий формат

X0, X1, X2, ...., Y
0.1, 1.2, -0.2, ..., 1.1
0.2, 0.5, 0.4, ..., -0.3
-0.5, 0.3, 0.3, ..., 0.1

У меня есть следующий код (пока) для получения строкиз файла и токенизации каждой строки через запятую, чтобы получить образцы.В настоящее время он не заполняет массивы X и Y и не присваивает значения num и dimx

val X = new Array[Array[Double]](num,dimx)
val Y = new Array[Double](num)

def readDataFromFile(filename: String) {
    var firstTime = true
    val lines = fromFile(filename).getLines
    lines.foreach(line => {
        val tokens = line split(",")
        if(firstTime) {
            tokens.foreach(token => // get header titles and set dimx)
            firstTime = false
        } else {
            println("data")
            tokens.foreach(token => //blah, blah, blah...)
        }
    })
}

Очевидно, что это проблема, потому что, хотя я могу обнаруживать и использовать dimx на лету, я не знаю num a priori .Также повторяющиеся токены. Foreach не очень элегантны.Я мог бы сначала отсканировать файл и определить размеры, но это похоже на неприятный путь.Есть ли способ лучше?Заранее спасибо

Ответы [ 3 ]

3 голосов
/ 17 февраля 2011

Там нет ничего встроенного, что скажет вам размер ваших данных.Почему бы не сделать так, чтобы метод возвращал ваши массивы, а не объявлял их снаружи?Таким образом, вы также сможете лучше обрабатывать ошибки.

case class Hxy(headers: Array[String], x: Array[Array[Double]], y: Array[Double]) {}
def readDataFromFile(name: String): Option[Hxy] = {
  val lines = io.Source.fromFile(name).getLines
  if (!lines.hasNext) None
  else {
    val header = lines.next.split(",").map(_.trim)
    try {
      val xy = lines.map(_.split(",").map(_.trim.toDouble)).toArray
      if (xy.exists(_.length != header.length)) None
      else Some( Hxy(header, xy.map(_.init), xy.map(_.last)) )
    }
    catch { case nfe: NumberFormatException => None }
  }
}

Здесь, только если у нас есть правильно сформированные данные, мы возвращаем соответствующие массивы (полезно упакованные в класс кейсов);в противном случае мы возвращаемся None, поэтому мы знаем, что что-то пошло не так.

(Если вы хотите узнать, почему это не сработало, замените Option[Hxy] чем-то вроде Either[String,Hxy] и верните Right(...)вместо Some(...) при успехе, Left(message) вместо None при неудаче.)


Редактировать: если вы хотите, чтобы значения (не только размеры массива) были неизменяемыми, то вы 'мне нужно сопоставить все с Vector где-нибудь по пути.Я бы, вероятно, сделал это на последнем шаге, когда вы помещаете данные в Hxy.

0 голосов
/ 17 февраля 2011

Используйте Array.newBuilder. Я предполагаю, что заголовок уже извлечен.

val b = Array.newBuilder[Array[Double]]
lines.foreach { b += _.split(",").map(_.toDouble) }
val data = b.result

Если вы хотите быть неизменным, возьмите некоторую неизменную реализацию IndexedSeq (например, Vector) вместо Array; строители работают над всеми коллекциями.

0 голосов
/ 17 февраля 2011

Array, как в Java, является изменяемым.Таким образом, вы не можете иметь неизменный массив.вам нужно выбрать между Array и неизменностью.Один из способов достижения цели без foreach es и var s похож на следующий:

// simulate the lines for this example
val lines = List("X,Y,Z,","1,2,3","2,5.0,3.4") 
val res = lines.map(_.split(",")).toArray
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...