我想编写一个函数,它接受一个列表并根据函数的输出构造一个特定长度的列表的子集。
如果我只是对排序列表 xs 的前 50 个元素感兴趣,那么我会使用fst (splitAt 50 (sort xs)).
但是,问题在于我的列表中的元素依赖于同一列表中的其他元素。如果我选择元素 p,那么我也必须选择元素 q 和 r,即使它们不在我列表的前 50 个元素中。我正在使用一个函数 finderFunc,它从列表 xs 中获取一个元素 a 并返回一个包含元素 a 及其所有必需元素的列表。finderFunc 工作正常。现在,挑战是编写一个函数,该函数基于 finderFunc 的多个输出构建一个总长度为 50 的列表。
这是我的尝试:
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
我意识到上面的 if 语句在某些情况下不会给我一个正好包含 50 个元素的列表。目前,这不是主要问题。问题是我的功能完成根本无法正常工作,正如我所期望的那样。它不仅会在输出列表中产生重复的元素,而且有时会远远超过我希望在列表中拥有的元素总数。
这种写法,我通常用一个空列表来调用它,例如:finish xs []
,这样它建立的列表就以一个空列表开始。