Home > Mobile >  Haskell function that takes the list of values and a list of names as input and returns the common v
Haskell function that takes the list of values and a list of names as input and returns the common v

Time:02-24

I'm trying to take an input, which I will call "Names", and use it to get an output, "Values" from a list in which "Value" is all lists that contain the given "Name". For example, if the list of lists is:

listOfLists = [("Name1", [Value1]), ("Name2", [Value2, Value3]), ("Name3", [Value1, Value2, Value3])]

and I give the input "Name 1, Name3" it will return "Value 1", as that is the value found in each.

Currently, what I have is this:

find_languages [] [] = []
find_languages ((x, y):xs) (courses) = filter ((x `elem` courses)((x, y):xs))

This is not working and I'm hoping for some tips. Some notes:

  • There should be no recursion
  • I can only use the Prelude Library
  • I can use a function I have already written, commons_all, which returns all common values across a list of lists - this should make it easy but I'm not sure how to implement it.
commons_all :: Eq a => [[a]] -> [a]
commons_all [] = []
commons_all (x:xs) = foldl commons x xs

The expected form will be

find_languages :: (Eq a1, Eq a2) => [(a2, [a1])] -> [a2] -> [a1]

Currently, this isn't the form the function takes.

CodePudding user response:

What you desire is to extract just the relevant value lists from listOfLists and pass them to commons_all. This can be done in three steps.

  1. obtain only the elements of listOfLists that have a name in courses. This can be done with filter and elem like your attempt so far, but you will not need to destructure the list argument, and instead will need to provide a function as the first argument to filter
  2. Extract only the value parts of the filtered lists. This can be done with map and a function with the type (a, b) -> b
  3. use commons_all on that result

Your final answer will likely look something like

find_languages list courses = commons_all $ map (something) $ filter (something) list

CodePudding user response:

First, let's find any tuples in listOfLists with one of the specified names. Our filter function first needs to extract the name using the fst function, then checks to see if it's an element of names.

Prelude> commonVals names lst = filter ((`elem` names) . fst) lst
Prelude> commonVals ["Name1", "Name3"] listOfLists
[("Name1",["Value1"]),("Name3",["Value1","Value2","Value3"])]

Having done that, we map snd to the results to get the values.

Prelude> commonVals names lst = map snd $ filter ((`elem` names) . fst) lst
Prelude> commonVals ["Name1", "Name3"] listOfLists
[["Value1"],["Value1","Value2","Value3"]]

Now that we have this, we just need to write an intersect function and fold it over the results.

Prelude> :{
Prelude| commonVals names lst = foldl1 intersect $ map snd $ filter ((`elem` names) . fst) lst
Prelude|    where
Prelude|       intersect a b = filter (`elem` b) a
Prelude| :}
Prelude> commonVals ["Name1", "Name3"] listOfLists
["Value1"]

All of this can readily be accomplished with Prelude functions and no explicit recursion.

  • Related