Home > Net >  How can I search and edit tuples in a list of tuples with more than 2 elements?
How can I search and edit tuples in a list of tuples with more than 2 elements?

Time:07-23

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.

  1. Write a function that given a Sale returns the sale count.

    saleCount :: Sale -> Integer
    saleCount (first, last, count) = undefined    -- to do
    
  2. 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
    
  3. 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
  • Related