I have the following tuple representing a 2D matrix in Haskell
let a =[(1,2,3),(4,5,6),(7,8,9)]
How can I access each index individually? (e.g. a[1][1], a[0][1] etc.)
Is there a better way to interpret 2D arrays in haskell?
Here's an example of how to create and index an immutable 2D array using the standard Data.Array module:
Prelude> import Data.Array
Prelude Data.Array> let a = array ((0,0),(2,2)) [((i,j),3*i+j)| i <- [0..2], j <- [0..2]]
Prelude Data.Array> a ! (1,1)
4
More information can be found on the Haskell Wiki.
If you're going to be doing this a lot --- working with matrices, arrays, etc. --- then it's probably best to follow one of Mikhail's suggestions.
If you're simply curious about how to go about doing this though, it basically comes down to pattern matching. One thing you can do is use the !! function to get a zero-indexed element from a list (the row in this case) and then you would have to pattern match to get the specific element from the tuple.
For example, in the following code, getRow fetches the specific row using !!, and then getElem returns the particular tuple element, so that ultimately getElem a 1 1 == 5 for example. You would of course have to add some code to handle out-of-bounds indices:
getRow :: [(Integer, Integer, Integer)] -> Int -> (Integer, Integer, Integer)
getRow matrix row = matrix !! (row :: Int)
getElem :: [(Integer, Integer, Integer)] -> Int -> Int -> Integer
getElem matrix row column
| column == 0 = x
| column == 1 = y
| column == 2 = z
where (x, y, z) = getRow matrix row
Related
I wrote a Haskell function to generate a list of tuples.
defineIndices :: Int -> Int -> [(Int,Int)]
defineIndices n m = [(i,j) | i <- [1..n], j <- [1..m]]
The function has the following behaviour.
λ> defineIndices 2 3
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3)]
It turns out that I require the function which behaves as the following:
λ> defineIndices2D 2 3
[[(1,1),(1,2),(1,3)],[(2,1),(2,2),(2,3)]]
In which defineIndices2D returns a list of list of (Int,Int) with dimensions n*m. I am a little bit stuck here, and I was wondering how my existing solution could be altered to produce a list of a higher order.
My end goal is to generate a list of x,y indices to use as the key for values in a Data.Map Map.
You can nest list comprehension, you thus make an outer list comprehension which will enumerate over the value for m, and you each time yield a list you produce with another list comprehension expression:
defineIndices2D :: Int -> Int -> [[(Int,Int)]]
defineIndices2D n m = [ [(i,j) | j <- [1..m]] | i <- [1..n]]
For a 2×3 grid, this thus produces:
Prelude> defineIndices2D 2 3
[[(1,1),(1,2),(1,3)],[(2,1),(2,2),(2,3)]]
Please jump to edit:
I have to deal with a problem in my homework, maybe I am completely wrong on that one but I'm new to functional programming.
I have a 5x5 Matrix with Strings in it, I want to read them out, transform them to a data element and applying it to a new matrix.
I am using a recursive approach because I want to add the position of the String into the Data element!
here is what I tried:
cycleMatrix :: Int -> Int -> [[String]] -> [[Data]]
cycleMatrix 0 0 matrix = (strToData 0 0 (matrix !! 0) !! 0))
cycleMatrix n 0 matrix = (cycleMatrix (n - 1) 0 matrix):(strToData n 5 ((matrix !! n) !! 5))
cycleMatrix n m matrix = (cycleMatrix n (m - 1) matrix):(strToData n n ((matrix !! n) !! m))
with strToData I am geting the string from the matrix and passing the x and y returning a Data Object (thats working)
At the moment I am just trying to add every element to an Array but I really want to start a new list every time I am getting to zero on m (after cycleMatrix n 0 matrix)
My questions are: Is this the way to go and how do I append this element in a correct way?
Edit: Okay I finally got it to work by splitting the functions(thx to Rudi for telling me not to do everything at once)
But my questions still stands. I now have 8 lists full with Data elements
I can append them all to a List with [] ++ [], but is there a way to create a matrix out of the lists like [] : [] (adding a list as element to a list)?
I would tackle this problem by enumerating the inner lists into (x, data) tuples¹, then enumerate this enumeration into (y, [x-lists]). This then is the starting point to convert this into the desired format.
You can load this file in ghci with :load file.hs, and play with the different functions there.
¹from your edit I guess that this is what you already did
example :: [[String]]
example = [
["as", "df", "ghj"],
["xx", "yy"]
]
-- add a position number to each list element. Beware
-- that this starts with 1
enumerate :: [a] -> [(Int, a)]
enumerate = zip [1..]
-- does the enumeration, but does not transform the
-- data into the desired format. I put it here, so that
-- the functionality of the different functions is
-- better to understand.
kindofEnumarate2d :: [[a]] -> [(Int, [(Int, a)])]
kindofEnumarate2d = enumerate . map enumerate
-- convert a row of (y, [(x, value)]) tuples into a
-- [((x,y), value)] list
helper :: (Int, [(Int, a)]) -> [((Int, Int), a)]
helper (y, xs) = [((x, y), s) | (x, s) <- xs]
-- transform each row of the "kind-of" transformed
-- rows into the desired format.
enumerate2d :: [[a]] -> [[((Int, Int), a)]]
enumerate2d = map helper . kindofEnumarate2d
I am new to Haskell and I am trying some stuff out. I am having some trouble comparing tuples elements.
Let's say I have a tuple [(1,3),(2,1),(4,4)].
I want to compare each pair index with each other and save some data into a counter value and return that value.
For example what I want is this:
Tuple: [(a,b),(c,d),(e,f)]
When a>b I want to add 3 to the counter.
When a==b I want to add 1 to the counter.
Otherwise add 0 to the counter. Same for (c,d) and (e,f).
After iterating through my tuples I want to return the counter.
So in my example I have tuple [(1,3),(2,1),(4,4)].
The function should do
Since 1<3 add 0 to counter.
Since 2>1 add 3 to counter.
Since 4=4 add 1 to counter.
And after all return 0+3+1 = 4.
Any ideas? Thank you in advance!
(Edit)
calculateWins :: [(Int,Int)]->Int
calculateWins d ((a,b) :xs) = x
where x
|a>b = 3
|a==b = 1
|otherwise = 0
This looks like the point system of a soccer cup (and some other sports). Instead of implementing a function that calculates the sum, we better first aim to calculate something that calculates the score for one such tuple, so something like:
score :: Ord a => (a, a) -> Int
By using a as type, we can use any type of values, as long as we can compare them (the Ord type constraint). So we can write something like:
score (x, y) = -- ...
now in case x > y, then the score is 3 points, in case x == y, then the score is 1 point, and finally in case x < y (otherwise), then the score is 0 points, so we can write it as:
score :: Ord a => (a, a) -> Int
score (x, y) | x > y = 3
| x == y = 1
| otherwise = 0
So now we can perform a map score to calcuate a list of scores, and by using sum, we can calculate the sum of those points, like:
calculateWins :: Ord a => [(a, a)] -> Int
calculateWins = sum . map score
Hint: use a function of type (a -> b) -> [a] -> [b] to transform the list of tuple into a list of your summands (3 or 1 or 0), and use another function of type [a] -> a to get the sum.
The Hoogle is a very nice site for looking up Haskell functions, both by name and by signature.
Please do try these things out before simply asking for the complete code; that helps neither of us.
I have array of x,y coordinates and char elements. I need function to get list of n chars at specified coordinates toward direction. I wrote it in recurrent way:
import Data.Array
exampleArray = array ((1,1),(2,2)) [((1,1),'a'), ((1,2),'b'), ((2,1),'c'), ((2,2),'d')]
-- 1 2
-- +---+---+
-- 1 | a | b |
-- +---+---+
-- 2 | c | d |
-- +---+---+
f :: Array (Int, Int) Char -> Int -> (Int, Int) -> (Int, Int) -> [Char]
f _ 0 _ _ = []
f arr n (x,y) (dirX, dirY) = (arr ! (y,x)) : f arr (n-1) (x+dirX,y+dirY) (dirX, dirY)
-- ac
list = f exampleArray 2 (1,1) (0,1) -- get 2 chars from array at 1,1 toward E
-- cb
list2 = f exampleArray 2 (1,2) (1,(-1)) -- get 2 chars from array at 1,2 toward NE
It works, but it is too slow and I am wondering how to optimize it?
Array is slow, so your first step should be to port to the vector package. Use the unboxed variant, as the default "boxed" representation allocates heap storage for each value and stores a pointer to it. There is no such thing as a 2-d vector so you will have to write code to transform your coordinate pairs into locations in a 1-d vector. If that still isn't fast enough then access using the unsafeIndex function and its relatives, which don't do bounds checking (but do not call up that which you cannot put down).
See also this question.
This is a homework assignment first off. We are given a newtype Matrix which is the professor's implementation of an abstract Matrix. My main issue is how do you create a list of type Matrix. The first function fillWith which I need to implement takes a tuple which is (number of rows, number of columns) of the matrix to create and the data to place at each index.
module Matrix (Matrix, fillWith, fromRule, numRows, numColumns,
at, mtranspose, mmap, add, mult)
where
-- newtype is like "data", but has some efficiency advantages
newtype Matrix a = Mat ((Int,Int),(Int,Int) -> a)
--fillWith :: (Int,Int) -> a -> (Matrix a)
--fillWith ix val = Mat ((,
--trying to create a row of type Matrix
row_matrix :: [a] -> Matrix a
row_matrix ls = Mat ((1, length ls), (\x y -> if x > 1 then undefined else ls !! (y-1)))
You are just missing some parens and a comma:
row_matrix ls = Mat ((1, length ls), (\(x,y) -> if x > 1 then undefined else ls !! (y-1)))
^-^-^--- add these
Mat is a tuple where:
the first element is itself a tuple, and
the second element is a function taking a tuple to a value of type a
You may always use a where or let clause to simplify the construction of values, e.g.:
row_matrix as = Mat (bounds, accessor)
where bounds = (1, length as)
accessor (i,j) = if i > 1 then undefined else as !! (j-1)
Using a where clause makes the code a lot more readable.
To implement fillWith I would follow the same recipe:
fillWith bounds val = Mat (bounds, accessor)
where accessor (i,j) = ???
I think it's obvious now what the ??? should be.