I have a list of tuples
type Sales = (String, String, Integer)
testData :: [Sales]
testData = [("Jack", "Hill", 2), ("Susan", "Smith", 5), ("Steve", "Johnson", 6)
How can I write a function that would search through the list of tuples given the first and last names and output the number, and let me edit that number?
I'm trying to have something like:
recordSale "Jack" "Hill" -- and the function return 2
And another which would do:
addSale "Jack" "Hill" -- and it would add 1 to the database corresponding to the name
So far I've tried
recordSale tData Fname Lname= find (\(Fname, Lname, _) tData
recordSale tData Fname Lname = [(Fname, Lname, map (\tData -> tData 1) sales) | (Fname, Lname, sales) <- tData]
nothing seems to work though, and most help I find only works with tuples with 2 elements, not 3.
CodePudding user response:
It might be worthwhile to use a Data.Map
. If you want to stick with tuples you can break it into smaller step.
Write a function that given a
Sale
returns the sale count.saleCount :: Sale -> Integer saleCount (first, last, count) = undefined -- to do
Write a function that given a name, checks if the passed tuple matches. (This is commonly called a predicate and will help you in the next step.)
isMatching :: String -> String -> Sale -> Bool isMatching first last (saleFirst, saleLast, saleCount) = undefined -- to do
Use
find @[] :: (a -> Bool) -> [a] -> Maybe a
. While trying with find the question will arise what you want to happen, if the list does not contain or tuple or multiple tuples.
For updating the list you can have a look at Replace individual list elements in Haskell?
CodePudding user response:
As a side note, the example testData is missing the closing square bracket.
A function to search the testData is shown below.
type Sales = (String, String, Integer)
testData :: [Sales]
testData = [("Jack", "Hill", 2), ("Susan", "Smith", 5), ("Steve", "Johnson", 6)]
findNumber:: [Sales] -> String -> String -> Integer
findNumber (x:xs) name1 name2 =
findNumberIter (x:xs) name1 name2 (-1)
where
findNumberIter [] _ _ number = number
findNumberIter (x:xs) name1 name2 number =
if xname1 == name1 && xname2 == name2 then
findNumberIter xs name1 name2 xnumber
else
findNumberIter xs name1 name2 number
where
(xname1,xname2,xnumber) = x
main = putStrLn $ show $findNumber testData "Jack" "Hill"
We run a tail recursion, going through the elements (x:xs)
one by one. For each element, we test against name1
and name2
supplied, and if found replace the output number with the matching number.
Notes:
- This will return the last match. You may want the first match, or perhaps you want all matches
- This assumes a no match value of -1. You may wish to change the function to return a
Maybe
value instead - The search uses a local definition of the recursion,
findNumberIter
, and hides it so that the user interface is cleaner - Each element
x
in the list is split out into separate values using a pattern match - There is almost certainly a cleaner and simpler way of doing this, but it is fine for a pedagogical approach