如何获得列表清单中的最短列表?
我有
shortest :: [[a]] -> [a]
shortest [] = []
我真的不知道从那里去哪里说实话 感谢任何帮助
答案 0 :(得分:6)
首先你已经拥有了:
shortest [] = []
我实际上并不喜欢这个,因为这意味着
之间没有区别shortest []
和
shortest [[]]
但是,如果你喜欢这种行为,那么Data.List的minimumBy
的类型为
(a -> a -> Ordering) -> [a] -> a
因此,我们首先需要使用(a -> a -> Ordering)
compare
以及Data.Function中名为on
的有用小函数。 on
就像一个“喷嘴”,在将它们输入另一个函数之前将函数应用于2个参数。
cmp = compare `on` length
这只是给了我们
shortest = minimumBy cmp
但是当给出一个空列表时,这会中断
shortest [] = []
shortest ls = minimumBy cmp ls
shortest [] = Nothing
shortest ls = Just $ minimumBy cmp ls
答案 1 :(得分:2)
这是一个可以处理无限列表的版本,平均花费的时间最少(无论最短列表的位置如何)
此解决方案并行地向下遍历列表,这避免了首先读取非常长(或无限)的列表。如果所有列表都是无限的,则此解决方案可能会崩溃。但是,由于它是尾递归的,所以你不应该耗尽堆栈空间,这个解决方案应该可以在非常长但有限的列表上工作。
shortest :: [[a]] -> [a]
shortest [] = []
shortest [soleList] = soleList
shortest lists = lists !! ((fst $ head $ winner) - 1)
where
winner = shortest' $ zipWith (,) [1..] lists
shortest' :: [(Int, [a])] -> [(Int, [a])]
shortest' plist = if (not $ null nullList)
then nullList
else shortest' $ map (\(index, list) -> (index, tail list))
$ filter (not . null . snd) plist
where
nullList = filter (null . snd) plist
请注意当出现多个最短列表时会发生什么:它会返回遇到的第一个列表。这可能很好,但您可能实际上想要返回多个列表。但是,由于您只返回一个列表,因此超出了当前定义的问题范围。
编辑------------ 进一步思考,一旦我们得出结论,我们没有最短的列表,那么我们就知道没有一个列表是空的。因此,最短的'可以简化为:
shortest' :: [(Int, [a])] -> [(Int, [a])]
shortest' plist = if (not $ null nullList)
then nullList
else shortest' $ map (\(index, list) -> (index, tail list)) plist
where
nullList = filter (null . snd) plist
答案 2 :(得分:1)
我试着逐步解释如何“手动”实现这个功能。
这个问题已经包含了空列表清单的案例。
shortest :: [[a]] -> [a]
shortest [] = []
不确定这是完美的,但让我们保持原样。
我们必须为包含一个列表的列表添加一个案例。
shortest [soleList] = ...
显然,如果只有一个列表,那么一个列表也是最短的列表。
shortest :: [[a]] -> [a]
shortest [] = []
shortest [soleList] = soleList
我们还需要为更大的列表列表添加一个案例。
shortest (firstList : remainingLists) = ...
最短列表的位置有两种选择:最短列表为firstList
,或最短列表为remainingLists
中的列表之一。如果是后者,那么它不仅仅是remainingLists
中的任何列表,而是那里的最短列表。所以我们需要在remainingLists
上进行递归调用。
shortest (firstList : remainingLists) =
... firstList ... shortest remainingLists ...
我们应该如何填补......?我们只选择两个列表中较短的一个。
shortest :: [[a]] -> [a]
shortest [] = []
shortest [soleList] = soleList
shortest (firstList : remainingLists) =
shortestOfTwo firstList (shortest remainingLists)
我们如何选择两个列表中较短的一个?
shortestOfTwo :: [[a]] -> [[a]] -> [[a]]
shortestOfTwo firstList secondList = ...
我们只是比较它们的长度!
shortestOfTwo firstList secondList =
if length firstList < length secondList
then firstList
else secondList
这应该有效,但这里有一些关于如何改进它的想法:
length
的频率是多少?shortest [[1, 2, 3], [1..]]
?答案 3 :(得分:0)
这个解决方案很大程度上取决于蒂姆的答案。
import Data.List (find)
shortest :: [[a]] -> Maybe [a]
shortest lists
= fmap fst . find (null . snd) . zip lists
. head . filter (any null)
. iterate (map (drop 1)) $ lists
你必须向后阅读shortest
的正文。最后一行不断从每个列表中删除一个元素。当看到第一个空列表时,最后一行停止该过程。并且第一行选择首先变为空的原始列表。
与蒂姆解决方案的不同之处:
shortest [[1..]]