Haskell Add Function Return to List Until Certain Length
- by kienjakenobi
I want to write a function which takes a list and constructs a subset of that list of a certain length based on the output of a function.
If I were simply interested in the first 50 elements of the sorted list xs, then I would use fst (splitAt 50 (sort xs)).
However, the problem is that elements in my list rely on other elements in the same list. If I choose element p, then I MUST also choose elements q and r, even if they are not in the first 50 elements of my list. I am using a function finderFunc which takes an element a from the list xs and returns a list with the element a and all of its required elements. finderFunc works fine. Now, the challenge is to write a function which builds a list whose total length is 50 based on multiple outputs of finderFunc.
Here is my attempt at this:
finish :: [a] -> [a] -> [a]
--This is the base case, which adds nothing to the final list
finish [] fs = []
--The function is recursive, so the fs variable is necessary so that finish
-- can forward the incomplete list to itself.
finish ps fs
-- If the final list fs is too small, add elements to it
| length fs < 50 && length (fs ++ newrs) <= 50 = fs ++ finish newps newrs
-- If the length is met, then add nothing to the list and quit
| length fs >= 50 = finish [] fs
-- These guard statements are currently lacking, not the main problem
| otherwise = finish [] fs
where
--Sort the candidate list
sortedps = sort ps
--(finderFunc a) returns a list of type [a] containing a and all the
-- elements which are required to go with it. This is the interesting
-- bit. rs is also a subset of the candidate list ps.
rs = finderFunc (head sortedps)
--Remove those elements which are already in the final list, because
-- there can be overlap
newrs = filter (`notElem` fs) rs
--Remove the elements we will add to the list from the new list
-- of candidates
newps = filter (`notElem` rs) ps
I realize that the above if statements will, in some cases, not give me a list of exactly 50 elements. This is not the main problem, right now. The problem is that my function finish does not work at all as I would expect it to. Not only does it produce duplicate elements in the output list, but it sometimes goes far above the total number of elements I want to have in the list.
The way this is written, I usually call it with an empty list, such as: finish xs [], so that the list it builds on starts as an empty list.