Better way to write this function: list to matrix (= list of lists)
Is there a better way to write this function (i.e. in one line via folds)?
-- list -> rowWidth -> list of lists listToMatrix :: [a] -> Int -> [[a]] listToMatrix  _ =  listToMatrix xs b = [(take b xs)] ++ (listToMatrix (drop b xs) b)
No, although I wish
chunksOfwas in the standard library. You can get that from here if you want: https://hackage.haskell.org/package/split-0.2.3.2/docs/Data-List-Split.html
Note a better definition would be:
listToMatrix xs b = (take b xs) : (listToMatrix (drop b xs) b)
although this might compile to the same core. You could also use
splitAt, though again this is likely to perform the same.
listToMatrix xs b = let (xs,xss) = splitAt b xs in xs : listToMatrix xss
Yes, there is a better way to write this function. But I don't think that making it one line is going to improve anything.
Use the prepending operator
(:)instead of list concatenation
(++)for single-element prepending
[(take b xs)] ++ (listToMatrix (drop b xs) b)is inefficient. I don't mean inefficient in terms of performances, because the compiler probably optimizes that, but, here, you are constructing a list, and then calling a function on it (
(++)) which is going to deconstruct it by pattern matching. You could instead build your list directly using the
(:)data constructor, which allows you to prepend a single element to your list. The expression becomes
take b xs : listToMatrix (drop b xs) b
splitAtto avoid running through the list twice
import Data.List (splitAt) listToMatrix :: [a] -> Int -> [[a]] listToMatrix xs b = row : listToMatrix remaining b where (row, remaining) = splitAt b xs
Ensure the correctness of your data by using
listToMatrix :: [a] -> Int -> Maybe [[a]] listToMatrix xs b | length xs `mod` b /= 0 = Nothing | null xs = Just  | otherwise = Just $ row : listToMatrix remaining b where (row, remaining) = splitAt b xs
You can even avoid checking every time if you have the right number of elements by defining a helper function:
listToMatrix :: [a] -> Int -> Maybe [[a]] listToMatrix xs b | length xs `mod` b /= 0 = Nothing | otherwise = Just (go xs) where go  =  go xs = row : go remaining where (row, remaining) = splitAt b xs
Ensure the correctness of your data by using safe types
A matrix has te same number of elements in each row, whereas nested lists don't allow to ensure that kind of conditions. To be certain that every row has the same number of elements, you can either use a library such as
You can use this, the idea is to take all the chunks of the main list, it is a different approach but basicly do the same:
Prelude> let list2Matrix n xs = map (\(x ,y)-> (take n) $ (drop (n*x)) y) $ zip [0..] $ replicate (div (length xs) n) xs Prelude> list2Matrix 10 [1..100] [[1,2,3,4,5,6,7,8,9,10],[11,12,13,14,15,16,17,18,19,20],[21,22,23,24,25,26,27,28,29,30],[31,32,33,34,35,36,37,38,39,40],[41,42,43,44,45,46,47,48,49,50],[51,52,53,54,55,56,57,58,59,60],[61,62,63,64,65,66,67,68,69,70],[71,72,73,74,75,76,77,78,79,80],[81,82,83,84,85,86,87,88,89,90],[91,92,93,94,95,96,97,98,99,100]]
Actually this is a nice case for unfolding.
unfoldr, unlike folding a list, creates a list to a from a seed value by applying a function to it up until this function returns
Nothing. Until we reach the terminating condition that will return
Nothingthe function returns
ais the current generated item of the list and
bis the next value of the seed. In this particular case our seed value is the given list.
import Data.List chunk :: Int -> [a] -> [[a]] chunk n = unfoldr (\xs -> if null xs then Nothing else Just (splitAt n xs)) *Main> chunk 3 [1,2,3,4,5,6,7,8,9] [[1,2,3],[4,5,6],[7,8,9]] *Main> chunk 3 [1,2,3,4,5,6,7,8,9,10] [[1,2,3],[4,5,6],[7,8,9],]