【问题标题】:Getting combination pairs of list elements获取列表元素的组合对
【发布时间】:2019-06-16 08:20:02
【问题描述】:

我正在尝试获取列表的所有组合。 [1,2,3] 的结果应该是 [(1,2),(1,3),(2,3)]。然而,我在下面的实现给出了[(1,2),(2,3)]

parings [d] = []
parings (y:ys) = (y, head ys): parings ys

【问题讨论】:

标签: list haskell


【解决方案1】:

9000 的回答中提到的列表理解可以很容易地分解为map 调用。

pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = map (\y -> (x, y)) xs ++ pairwise xs

每个列表理解都可以分解为mapfilterconcatMap 的某种组合,可能还散布着一些let 绑定。这样做是学习如何操作函数的好练习。

【讨论】:

    【解决方案2】:

    这是使用来自Data.Listtails 的一种实现:

    import Data.List
    
    pairings :: [a] -> [(a, a)]
    pairings = concatMap makePairs . tails
        where
        makePairs [] = []
        makePairs (x:xs) = fmap ((,) x) xs
    

    注意事项:

    • 我不知道tails 对你来说算不算“特殊导入”——虽然它不在 Prelude 中,但可以在 base 库中找到,随时可用。

    • 要查看tails 的作用,请尝试tails [1..3]

    • ((,) x) 只是写(\y -> (x, y)) 的简洁方式。如果你觉得它难看,你可以写更长的版本,或者启用TupleSections扩展并将其拼写为(x,)

    • makePairs 可能在没有显式递归的情况下写成...

      makePairs = maybe [] (\(x, xs) -> fmap ((,) x) xs) . uncons
      

      ...uncons 也可以在 Data.List 中找到。

    • 此处答案中的所有实现都有一个不小的问题:它们将消耗的列表段保留在内存中。要了解我在说什么,请在 GHCi 中运行 head . drop 8000000 $ pairings [1..] 时观察内存使用情况。我对是否有解决方法没有信心——例如,一个简单的concat . tails 似乎遇到了同样的问题,而fmap makePairs . tails 没有(即使head . drop (10^9) . head . drop (10^9) . fmap makePairs . tails $ [1..] 也不会吃掉你所有的记忆)。

    【讨论】:

      【解决方案3】:

      我不知道你为什么反对列表推导;有了它们,解决方案就很简单了:

      pairwise :: [a] -> [(a, a)]
      pairwise [] = []
      pairwise (x:xs) = [(x, y) | y <- xs] ++ pairwise xs
      

      如果需要,您可以通过显式尾递归将理解分解为单独的函数。

      (也可以通过保留++ 两边的参数并拥有一个累加器参数来使整个事情成为尾递归。)

      【讨论】:

      • 很棒的负鼠!不使用列表理解的原因是因为我正在挑战自己学习算法以及内部通过它们的内容。如果有一天列表理解中断了,我们需要使用正常的算法,哈哈,我不知道我累了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-02
      • 2016-12-19
      相关资源
      最近更新 更多