从文本中获取矩阵的功能方法

时间:2010-03-26 11:36:54

标签: arrays scala functional-programming matrix

我正在尝试解决一些Google Code Jam问题,其中输入矩阵通常以这种形式给出:

2 3 #matrix dimensions
1 2 3 4 5 6 7 8 9 # all 3 elements in the first row
2 3 4 5 6 7 8 9 0 # each element is composed of three integers

其中矩阵的每个元素由三个整数组成。所以这个例子应该转换为

#!scala
Array(
     Array(A(1,2,3),A(4,5,6),A(7,8,9),
     Array(A(2,3,4),A(5,6,7),A(8,9,0),
)

必要的解决方案将是

形式
#!python
input = """2 3
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 0
"""
lines = input.split('\n')
class Aclass:
    def __init__(self,a,b,c):
        pass

print lines[0]
m,n = (int(x) for x in lines[0].split())
array = []
row = []
A = []
for line in lines[1:]:
    for elt in line.split():
        A.append(elt)
        if len(A)== 3:
            row.append(Aclass(A[0],A[1],A[2]))
            A = []
    array.append(row)
    row = []

from pprint import pprint
pprint(array)

我想到的功能解决方案是

#!scala
def splitList[A](l:List[A],i:Int):List[List[A]] = {
  if (l.isEmpty) return List[List[A]]()
  val (head,tail) = l.splitAt(i)
  return head :: splitList(tail,i)
}

def readMatrix(src:Iterator[String]):Array[Array[TrafficLight]] = {
  val Array(x,y) = src.next.split(" +").map(_.trim.toInt)
  val mat = src.take(x).toList.map(_.split(" ").
          map(_.trim.toInt)).
          map(a => splitList(a.toList,3).
                map(b => TrafficLight(b(0),b(1),b(2))
                 ).toArray
                ).toArray
    return mat
  }

但我真的觉得这是错误的方式,因为:

  1. 我正在为每一行使用功能List结构,然后将其转换为数组。整个代码似乎不那么有效了
  2. 我发现它比python解决方案更不优雅,更不易读。由于它们都使用相同的语义,因此哪些map函数对哪些函数进行操作更难。
  3. 这样做的正确功能方法是什么?

4 个答案:

答案 0 :(得分:7)

val x = """2 3
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 0
"""

val a = x split "\n" map (_.trim.split(" "))
val rows = a(0)(0).toInt
val columns = a(0)(1).toInt

val matrix = (a drop 1) map (_ grouped columns toList) toList

打印结果:

matrix.map(_.map(_.mkString("(",",",")")).mkString("(",",",")")).mkString("\n")

res1: String =
((1,2,3),(4,5,6),(7,8,9))
((2,3,4),(5,6,7),(8,9,0))

假设:

assert(rows == matrix.length)
assert(matrix.forall(_.forall(_.size == columns))) 

生成数组tabulate更合适:

val a = x split "\n" map (_.trim.split(" "))
val rows = a(0)(0).toInt
val columns = a(0)(1).toInt
val matrix = Array.tabulate(rows, a(1).size / columns, columns)(
  (i,j,k) => a(i +  1)(j * columns + k))

答案 1 :(得分:2)

这是适用于Scala 2.7的版本:

val x = """2 3
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 0
"""

val a = x.trim split "\n" map (_.trim.split(" "))
val rows = a(0)(0).toInt
val columns = a(0)(1).toInt

def intervals(n: Int) = (Stream from (0, n)) zip (Stream from (n, n))

val matrix = (a drop 1) map (v =>
  intervals(v.size / columns) 
  take columns 
  map Function.tupled(v.subArray) 
  toArray
) toArray

val repr = matrix map (
  _ map (
    _ mkString ("Array(", ", ", ")")
  ) 
  mkString ("Array(", ", ", ")")
) mkString ("Array(\n\t", ",\n\t", "\n)")

println(repr)

答案 2 :(得分:0)

我最近问了一个非常相似的问题。我想你会在那里找到答案。

find unique matrices from a larger matrix

输入以String开始,并在此过程中转换为一系列2D矩阵。

答案 3 :(得分:-1)

让我们尝试一下......似乎你不太担心语言,所以我只是描述它的代码。

所以我们将有我们的函数接受这个字符串,并返回一个多维数组。

funciton需要做的第一件事就是读取字符串,直到获得空格,然后将此子字符串转换为int并将其存储为“rows”,然后再次执行相同操作,但将其存储为“columns”。

接下来,它需要遍历字符串的其余部分,读出数字并将它们作为整数存储在数组中。

然后需要计算每个单元格的数量,这应该是“rows * columns / numbers_of_ints”这个除法应该是“16/5 = 3”而不是“16/5 = 1”或16/5 = 3.2222 ......“。

然后我们创建我们的长度行数组,其中每个元素都是一个长度为columsn的数组,其中每个元素都是长度为'每个单元格的数字'的数组。这个3D阵列让我们仍然可以访问存储的每个数字。

现在我们需要遍历每个单元格并将其数字放入其中。

for(i = 0 ; i < rows ; i = i + 1)
{
  for(j = 0 ; j < columns ; j = j + 1)
  {
    for(k = 0 ; k < numbers_per_cell ; k = k + 1)
    {
      matrix[i][j][k] = numbers[( i * columns ) + j + k]
    }
  }
}

你现在应该有一个矩阵,其中包含我们所有的数字作为单个int存储在数组中的某些位置。

应该看起来像

Array(
  Array(Array(1,2,3),Array(4,5,6),Array(7,8,9),
  Array(Array(2,3,4),Array(5,6,7),Array(8,9,0),
)

希望这会对你有所帮助。如果我需要更好地解释一下,或者有人提出建议,我会更新它。