如果我想在列表列表中找到最长的列表,最简单的方法可能是:
longestList :: [[a]] -> [a]
longestList = maximumBy (comparing length)
更有效的方法是预先计算长度:
longest :: [[a]] -> [a]
longest xss = snd $ maximumBy (comparing fst) [(length xs, xs) | xs <- xss]
现在,我想更进一步。对于正常情况,它可能不会更有效,但是你可以使用箭头来解决这个问题吗?我的想法基本上是,同时逐步浏览所有列表,并继续踩到你超越每个列表的长度,除了最长的。
longest [[1],[1],[1..2^1000],[1],[1]]
在上述(非常人为的)示例中,您只需要在每个列表中执行两个步骤,以确定列表[1..2^1000]
是最长的,而无需确定所述列表的整个长度。我是对的,这可以用箭头完成吗?如果是这样,那怎么样?如果没有,那么为什么不,以及如何实施这种方法?
答案 0 :(得分:4)
好吧,在我写这个问题的时候,我突然想到了一个实现这个问题的简单方法(没有箭头,嘘!)
longest [] = error "it's ambiguous"
longest [xs] = xs
longest xss = longest . filter (not . null) . map (drop 1) $ xss
除非有问题......它会删除列表的第一部分并且无法恢复它!
> take 3 $ longest [[1],[1],[1..2^1000],[1]]
[2,3,4]
需要更多簿记:P
longest xs = longest' $ map (\x -> (x,x)) xs
longest' [] = error "it's ambiguous"
longest' [xs] = fst xs
longest' xss = longest . filter (not . null . snd) . map (sndMap (drop 1)) $ xss
sndMap f (x,y) = (x, f y)
现在可行。
> take 3 $ longest [[1],[1],[1..2^1000],[1]]
[1,2,3]
但没有箭头。 :(如果可以用箭头完成,那么希望这个答案可以让你在某个地方开始。
答案 1 :(得分:3)
这是我能想到的最直接的实现。但是,没有涉及箭头。
我保留一对列表,其中第一个元素是原始列表,第二个元素是剩余的尾部。如果我们只剩下一个清单,我们就完成了。否则,我们会尝试获取所有剩余列表的尾部,过滤掉那些空的列表。如果有些人仍然存在,继续前进。否则,它们都是相同的长度,我们随意挑选第一个。
longest [] = error "longest: empty list"
longest xss = go [(xs, xs) | xs <- xss]
where go [(xs, _)] = xs
go xss | null xss' = fst . head $ xss
| otherwise = go xss'
where xss' = [(xs, ys) | (xs, (_:ys)) <- xss]
答案 2 :(得分:3)
考虑到这一点,有一个更简单的解决方案,它提供相同的性能特征。我们可以使用maximumBy
和懒惰长度比较函数:
compareLength [] [] = EQ
compareLength _ [] = GT
compareLength [] _ = LT
compareLength (_:xs) (_:ys) = compareLength xs ys
longest = maximumBy compareLength