1

次の形式のログ ファイルがあります。

3
1 2 3
1 2 3 
1 2 3
1 2 3
4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4

マトリックスの高さは常に同じであるため、単一の数字はマトリックスの幅を示します。また、同じログ ファイル内に複数のマトリックスが存在する場合があります。行列データを配列に解析したくありません。で行を読みましたscala.io.Source.fromFile(f).getLines.mkStringが、配列を埋めるのに苦労しています。

for(i <- 0 to 3) {
    for(j <- 0 to N-1) {
        matrix(i)(j) = ...
    }
}

行が、マトリックスにしたいのと同じ方法でインデックス付けされていた場合、これはそれほど難しくありません。しかし、行(n)に空白、改行が含まれている場合..何が間違っているのですか?

4

7 に答える 7

4

ステート マシンは必要ないと思います。以下は、ステート マシン ソリューションと形状と内容が同等のデータ構造を提供します。

import scala.io.Source

val input = Source.fromString(
  """|3
     |1 2 1
     |1 2 2
     |1 2 3
     |3 2 1
     |4
     |1 2 3 1
     |1 2 3 2
     |1 2 3 3
     |1 2 3 4""".stripMargin)

val matrices = input.getLines.grouped(5).map {
  case List(w, l1, l2, l3, l4) =>
    // feel free to use the value of `w.toInt` to do an assertion on the 4 lines
    List(l1, l2, l3, l4) map { _.split(' ').map(_.toInt).toList }
}

for (matrix <- matrices)
  println(matrix.map(_.mkString("[", ", ", "]")).mkString("\n"))

// prints:
// [1, 2, 1]
// [1, 2, 2]
// [1, 2, 3]
// [3, 2, 1]
// [1, 2, 3, 1]
// [1, 2, 3, 2]
// [1, 2, 3, 3]
// [1, 2, 3, 4]
于 2013-09-20T14:53:30.680 に答える
0

次の再帰的な解決策はどうですか?

val fixedHeight = 4

def readMatrices(lines: List[String]): List[Array[Array[Int]]] = {

  def readMatrices0(lines: List[String], result: ListBuffer[Array[Array[Int]]]): List[Array[Array[Int]]] = lines match {
    case None => result.toList
    case head :: tail =>
      val n = head.toInt 
      val mat = readMatrix(tail.take(fixedHeight))
      // check that the matrix has width n:
      require(mat.forall(_.length == n), "Incorrect width")
      readMatrices0(tail.drop(fixedHeight), result + mat)
  }

  def readMatrix(lines: List[String]): Array[Array[Int]] = 
    lines.map(_.split(' ').map(_.toInt).toArray

  readMatrices0(lines, new ListBuffer)
}

val mats = readMatrices(scala.io.Source.fromFile(f).getLines)
于 2013-09-20T17:31:19.810 に答える
0

OK、私は素晴らしいものを持っていると思います:

  • 行数が異なる行列を処理します(ポスターのログファイルに行番号が異なる行列があるに違いありません:-)
  • 入力全体を一度に解析するのではなく、段階的に解析します (したがって、それほど多くのメモリを使用しません)。
  • 入力の検証を可能にします

準備

最初の部分は、最初の回答とほぼ同じです。しかしzipWithIndex、入力の行番号を保持するために追加しました。

    import io.Source

    def rawInput = Source.fromString(
       """|3
          |1 2 1
          |1 2 2 
          |1 2 3
          |4
          |1 2 3 1
          |1 2 3 2
          |1 2 3 3
          |1 2 3 4""".stripMargin) // You would probably use Source.fromFile(...)

    type Matrix = List[Array[Int]]

    def parsedInput = rawInput.getLines().map(_.split(" ")).map(_.map(_.toInt)).zipWithIndex

イテレータ付きバージョン

このバージョンは、変更可能な状態を持つ従来の Java イテレータを使用します。機能的なスタイルではありませんが、非常に高速に実行されるはずです。

    def matrixIterator= new Iterator[Matrix] {
      val input = parsedInput

      var expectedNumerOfRows : Option[Int] = None

      override def hasNext = input.hasNext

      override def next() : Matrix = {
        import collection.mutable.MutableList
        var matrix : MutableList[Array[Int]] = MutableList()
        while (input.hasNext) {
          val (currentLine, lineNumber)=input.next()
          if (currentLine.size==1){
            expectedNumerOfRows=Some(currentLine.head)
            return matrix.toList
          }else{
            matrix+=currentLine
            expectedNumerOfRows.filter(_ != currentLine.size).foreach{ expected : Int =>
              //println(String.format("Warning in line %s: Expected %s columns, got %s", lineNumber+1, expected, currentLine.size))
            }
          }
        }
        return matrix.toList
      }
    }.next()

ストリーム付きバージョン

このバージョンは Scala ストリームを使用します。再帰的 (末尾再帰的ではありません) であり、変更可能な変数は使用しません。Iterator バージョンよりも少し遅くなるはずですが、はるかに読みやすくなっています。

    def matrixStream : Stream[Matrix] = {
      def matrix(input : Iterator[(Array[Int], Int)], numberOfColumns : Int, currentMatrix : Matrix) : Stream[Matrix] = {
        if (!input.hasNext) {
          currentMatrix #:: Stream.empty
        }else{
          val (line, number) = input.next()
          if (line.size == 1) {
            currentMatrix.reverse #:: matrix(input, line.head, List.empty)
          }else{
            //if (numberOfColumns != line.size) println(...)
            matrix(input, numberOfColumns, line :: currentMatrix)
          }
        }
      }
      matrix(parsedInput,0,List()).drop(1)
    }
于 2013-09-23T06:29:46.937 に答える
0

ステファンのコードは機能状態機械の素晴らしい例ですが、私は個人的にはこのようなものを好みます

import io.Source

val input = Source.fromString(
   """|3
      |1 2 1
      |1 2 2
      |1 2 3
      |1 2 4
      |4
      |1 2 3 1
      |1 2 3 2
      |1 2 3 3
      |1 2 3 4""".stripMargin)

type Matrix = List[List[Int]]

def readMatrix(list: List[Int], height: Int, width: Int): Matrix =  {
  list.take(height * width).grouped(width).toList
}

def readMatrices(list: List[Int]): List[Matrix] = {
  if (list.isEmpty) List()
  else readMatrix(list.tail, 4, list.head) :: readMatrices(list.drop(4 * list.head + 1))
}

def printMatrix(matrix: Matrix) = println(matrix.map(_.mkString("", ", ", "")).mkString("", "\n", "\n"))

val parsedMatrices = readMatrices(input.mkString.split("\\s+").map(_.toInt).toList)
parsedMatrices.foreach(printMatrix)
于 2013-09-20T15:00:12.490 に答える
-1

正規表現が役立ちます。

val space = " ".r
val arrayOfNumbersAsStrings = space.split(line)
val arrayOfNumbersAsInts = arrayOfNumbersAsStrings.map(_.toInt)

UPD

val arrayOfNumbersAsStrings = space.split(' ')
val arrayOfNumbersAsInts = arrayOfNumbersAsStrings.map(_.toInt)
于 2013-09-20T10:22:38.397 に答える
-1

正規表現がなくても:

for (i <- 0 to 3) {
  matrix(i) = line.split(" ")
}
于 2013-09-20T10:30:01.300 に答える