2010-03-26 3 views
3

Я пытаюсь решить некоторые проблемы, 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 для каждой строки, а затем преобразуйте ее в массив. Весь код выглядит намного менее efficeint
  2. Я нахожу его более менее элегантным и гораздо менее читаемым, чем решение python. Сложнее определить, какая из функций карты работает над тем, что, поскольку все они используют одну и ту же семантику.

Каков правильный функциональный способ сделать это?

+0

Будет ли scala быть языком тогда? Если не на каком языке вы используете? Я знаю, что вы после функционального способа сделать это, но хороший класс, вероятно, предоставит вам гораздо лучшее решение. – thecoshman

+0

@thecoshman - это язык, через который я передаю идеи FP. Мне это не нужно для практических целей, я просто изучаю FP. Я знаю Scala, а не Haskell, поэтому я использовал его, но я мог бы сделать это на каждом достаточно функциональном языке (даже python довольно функциональный). Возможно, действительно, эта задача больше подходит для императивного/OO-подхода, но я все еще ищу лучшее функциональное решение. –

+0

Как бы выглядели данные матрицы 3x2? –

ответ

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)) 
+0

Практически такая же идея, как и у меня, но вы разделили ее на имена переменных более красиво и использовали сгруппированную функцию 2.8. Я думаю, что у вас проблема с скобкой в ​​строке 'z foreach (assert (_.size == ' –

+0

О, и есть ли функциональный поддерживающий массив (вы вернули список, и массив может быть более эффективным). Создание списка и преобразование его в массив кажется мне неудобным. –

+0

'tabulate' - это здорово! Это не в 2,7, но, к счастью, люди, использующие 2,7, могут добиться того же самого результата с чуть более неудобным синтаксисом, используя 'fromFunction'. –

-1

Давайте попробуем это ... кажется, вы не слишком беспокоитесь о языке, поэтому я просто опишу его код.

поэтому у нас будет наша функция, которая принимает эту строку и возвращает многомерный массив.

Первое, что нужно сделать, это прочитать строку до тех пор, пока она не получит пробел, а затем преобразует эту вспомогательную строку в int и сохраняет ее как «строки», а затем повторяет то же самое, но сохраняет ее как «столбцы», ,

Далее нужно будет пропустить оставшуюся часть строки, считывая цифры и сохраняя их как int в массиве.

Затем необходимо рассчитать количество чисел на ячейку, которые должны быть «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), 
) 

Надеется, что это помогает вам. Я обновлю его, если мне нужно что-то объяснить, или у кого-то есть предложение.

+0

Это действительно важный императивный способ сделать это, но я искал функциональный способ. «matrix» здесь сохраняет свое состояние. –

+0

Я подразумевал, что вы бы это сделали, но это в функцию, чтобы вы могли назвать что-то вроде get_matrix ("" ​​2 3 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 0 "); и имеют 3D-массив вернулся к вам. – thecoshman

+1

Либо я не понимаю, что вы только что сказали, либо не согласны с понятием термина «функциональное программирование». http://en.wikipedia.org/wiki/Functional_programming В любом определении, которое я знаю, включение функций в функции не делает вашу программу более функциональной. –

2

Вот версия, работает на Sc ala 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) 
0

Я недавно задал вопрос, который очень похож. Я думаю, вы найдете там ответ.

find unique matrices from a larger matrix

вход начинается как String, так и в процессе превращается в серию 2D матриц.

Смежные вопросы