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.
- obtain only the elements of listOfLists that have a name in courses. This can be done with
filter
andelem
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 tofilter
- Extract only the value parts of the filtered lists. This can be done with
map
and a function with the type(a, b) -> b
- 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.