Reputation: 51
I am trying to write a function like this:
updateMatrix:: [[a]] -> a -> (x, y) ->[[a]]
This is supposed to take in a list of lists such as:
[ [1, 2, 3, 4],
[5, 6, 7, 8]]
and put the given element at the specified coordinates, so, given:
[ [1, 2, 3, 4],
[5, 6, 7, 8]] 9 (0, 1)
it should return
[ [1, 9, 3, 4],
[5, 6, 7, 8]]
I can't figure out how to do this without having to rebuild the whole matrix, please help!
Upvotes: 2
Views: 4360
Reputation:
Here’s a short one:
replace p f xs = [ if i == p then f x else x | (x, i) <- zip xs [0..] ]
replace2D v (x,y) = replace y (replace x (const v))
Now you can use it exactly like you wanted:
λ → let m = [[1, 2, 3, 4], [5, 6, 7, 8]]
λ → replace2D 9 (0, 1) m
[[1,2,3,4],[9,6,7,8]]
As others already said,
m
as a pointer to a linked list of pointers, and you can see why it’s slower than a pure stream of bytes. There are better libs that use something closer to the latter.m
. You can only build something out of m
.IORef
. But using it for this would be rather wrong. There are many other questions here on Stack Overflow, explaining its usage, pros and cons.Upvotes: 3
Reputation: 1543
You need to rebuild the matrix every time. So as long as you don't need high performance computing, you could use this legible implementation:
replace :: (a -> a) -> Int -> [a] -> [a]
replace f 0 (x:xs) = (f x):xs
replace f i (x:xs) = x : replace f (i-1) xs
replace f i [] = []
replace2D :: (a -> a) -> (Int, Int) -> [[a]] -> [[a]]
replace2D f (x,y) = replace (replace f y) x
Your function would be:
updateMatrix ll x c = replace2D (const x) c ll
Upvotes: 6
Reputation: 307
Being a purely functional language, Haskell requires you to return a "brand new" matrix when you update an item, so you need to rebuild the whole matrix indeed (if you're actually interested in matrix processing, cast a look at matrix library rather than implementing your own).
Beware, lists are not a good choice for such manipulations, but if you do it for educational purposes, start with implementing a function that "replaces" an element in [a]
, then use it twice (function composition can help there) in order to get your updateMatrix
function. Here is an answer that can help you on your way.
Upvotes: 1
Reputation: 11912
Here's an implementation:
updateMatrix :: [[a]] -> a -> (Int, Int) -> [[a]]
updateMatrix m x (r,c) =
take r m ++
[take c (m !! r) ++ [x] ++ drop (c + 1) (m !! r)] ++
drop (r + 1) m
But maybe this "rebuilds the whole matrix" as you say? Note that lists are not mutable in Haskell, so you can't destructively update one entry, if that's what you would mean by not "rebuilding the whole matrix".
Upvotes: 4