在 Haskell 中的列表列表中查找最短列表

Finding the shortest list in a list of lists in Haskell

我在使用 Haskell 编写的程序时遇到了一些困难。它背后的想法是递归地找到列表列表中的最短列表 return 。我已经成功地编写了程序,但我似乎无法弄清楚我在其中做错了什么。这些是我在尝试编译时遇到的错误:

这是我使用的代码:

shortest :: [[a]] -> [a]
shortest [] = []
shortest [y] = y
shortest (x:y:list)
   | length x > length y = shortest y:[list]
   | otherwise = shortest x:[list]

如果有人能指出我哪里出错了,将不胜感激!

我认为您只需要括号:shortest (y:list)x 情况相同。

: 的优先级使其读起来像 (shortest y) : list

list已经是你输入的尾巴了;您不需要(也不应该)将其包装在另一个列表中。

shortest (x:y:list) = shortest $ (if length x > length y then y else x) : list

在每一步中,问题只是从递归调用的输入中删除哪个元素 xy

另一种不需要两个基本情况的方法是只比较列表的头部和尾部递归的结果。

shortest [] = []
shortest (x:xs) = let s = shortest xs
                  in if length s < length x then s else x

最后,元组按字典顺序进行比较,因此您还可以通过使用长度标记每个列表、找到最小的标记值,然后提取原始列表来免除显式递归。

shortest = snd . minimum . map (\x -> (length x, x))

使用 Control.Arrow,您可以将 map 的参数写为 (length &&& id)

注意最后一种方法:由于列表也按字典顺序进行比较,如果您有多个长度最短的列表,最终结果将取决于列表值本身的比较方式。相比之下,前两个例子是稳定的;返回第一个这样的最短列表。


Daniel Wagner 指出了使用 minimum 的更好解决方案,即将每个元素包装在一个 Arg 值中,这样可以 单独比较两个列表 的长度,而不考虑列表的内容。

import Data.Semigroup
shortest xs = x where Arg _ x = minimum [Arg (length x) x | x <- xs]

Arg 基本上是一个 2 元素产品类型, 使用第一个元素作为其 Ord 实例,不像 (,)两者都用。

  shortest []=[]
  shortest [y] = y
  shortest (x:y:list)
   |length x > length y = shortest (y:list)            
   |otherwise = shortest (x:list)

这行得通 :),另外值得一提的是,如果列表中有 2 个或多个元素 "shortest",第一个元素将始终弹出。

   Prelude>shortest[[1],[2],[3]]
   [1]
import Data.List
import Data.Ord
shortest list = minimumBy (comparing length) list

免分:

shortest = minimumBy (comparing length)

这些库包含在 GHC 中。他们的名字说明了他们做得很好。也许为空列表添加一个单独的案例。