/ / Как да трансформираме списък на цели числа в матрица от истинни и грешни в Haskell - haskell

Как да преобразувате списък на цели числа в матрица на истината и фалшивата в Haskell - haskell

В това упражнение трябва да напиша функция, коятополучава списък на цели числа като аргумент и дава матрица или списък със списъци. Въпросът в правенето на матрицата е, че целите числа представляват числото Trueвъв всяка колона на матрицата. Например

[2,4,1]

трябва да бъде преведен на:

въведете описанието на изображението тук

който в системата е представен като списък със списъци:

[ [0,1,0], [0,1,0], [1,1,0], [1,1,1] ]

Тъй като не е лесно да се манипулират матрици (списък със списъци) по колони, използвах трик и завъртях матрицата на 90 градуса вляво, използвайки transpose поради което матрицата изглежда по-долу:

въведете описанието на изображението тук

Тогава разработих следния алгоритъм за решаване на проблема:

  1. Вземете първия елемент от списъка за въвеждане
  2. Създайте списък с дължина maximum xs (дължината на всеки списък е равна на максималния елемент в списъка)
  3. Сложете толкова много True в списъка, както определя първият елемент.
  4. Попълнете останалата част от списъка с False
  5. Направете същото за всички елементи и завъртете матрицата

Опитах да внедря две решения, но всяко от тях има проблем, който не мога да разреша:

  1. Този работи добре за първия елемент, но не знам как да го прилагам към всички елементи от списъка за въвеждане

    listToMatrix x = (replicate ((maximum x) - (head x)) False) ++ (replicate (head x) True)`
    
  2. Това работи за всички елементи, но не може да запази дължината на вътрешния списък, така че списъците да имат различна дължина.

    listToMatrix lst@(x:xs) = ((replicate ((maximum lst) - x) False) ++ (replicate x True)) : listToMatrix xs`
    

Въпрос 1: Как мога да накарам тези функции да работят с минимални промени?

Въпрос 2: Има ли по-елегантни и компактни решения?

Послепис Използвах 1 и 0 в матриците, за да ги направя по-четими, но в действителност са верни и неверни

Отговори:

3 за отговор № 1

Използвах следния подход, който е съвместим с вашия.

Както предложихте, ние използваме transpose в края, тъй като транспонираната матрица изглежда по-лесна за генериране.

f :: [Int] -> [[Bool]]
f xs = transpose (...)

След това, всеки елемент на xs трябва да генерира нов ред. Можем да използваме разбиране на списъка (направено по-долу) или да използваме алтернативно map.

f :: [Int] -> [[Bool]]
f xs = transpose [ row x | x <- xs ]
where row :: Int -> [Bool]
row x = ...

Както предлагате, ние също имаме нужда maximum за генериране на всеки ред, така че го изчисляваме веднъж:

f :: [Int] -> [[Bool]]
f xs = transpose [ row x | x <- xs ]
where m = maximum xs
row :: Int -> [Bool]
row x = ...   -- we know x and m, we need m-x Falses and x Trues

Сега просто трябва да адаптирате кода си.


3 за отговор № 2

Ето как ще го направя:

toMatrix" :: [[Bool]] -> [Int] -> [[Bool]]
toMatrix" acc xs
| or  bools = toMatrix" (bools : acc) (map pred xs)
| otherwise = acc
where bools = map (> 0) xs

toMatrix :: [Int] -> [[Bool]]
toMatrix = toMatrix" []

Просто и ясно. Няма нужда да се транспонира.

Ето визуализацията на моята програма. Ще използвам 0 и 1 за False и True съответно.

toMatrix [2,4,1] = toMatrix" []                                [ 2, 4, 1]
= toMatrix" [[1,1,1]]                         [ 1, 3, 0]
= toMatrix" [[1,1,0],[1,1,1]]                 [ 0, 2,-1]
= toMatrix" [[0,1,0],[1,1,0],[1,1,1]]         [-1, 1,-2]
= toMatrix" [[0,1,0],[0,1,0],[1,1,0],[1,1,1]] [-2, 0,-3]
= [[0,1,0],
[0,1,0],
[1,1,0],
[1,1,1]]

Когато се обаждаме toMatrix" acc xs първо изчисляваме bools = map (> 0) xs, Ако всички елементи на bools сте False тогава сме готови. Ние просто се връщаме acc, В противен случай добавяме bools до началото на acc и извадете по един от всеки елемент на xs, Изплакнете и повторете.

Няма нужда да следите най-големия елемент от xs и няма нужда да транспонирате матрицата. Simple.