Haskell:整数的列表组合

时间:2014-01-28 20:27:55

标签: haskell

我有一个给定的列表,例如[2, 3, 5, 587]我希望有一个完整的组合列表。所以想要[2, 2*3,2*5, 2*587, 3, 3*5, 3*587, 5, 5*587, 587]之类的东西。由于我在初学者级别与Haskell,我很好奇列表操作将如何。

此外,我很好奇如果基本列表的计算可能很昂贵,这将如何影响功能的成本? (如果我会认为列表有限制值,即<20)

Rem:列表的顺序可以在之后完成,但我真的不知道如果在函数内或之后更便宜。

3 个答案:

答案 0 :(得分:6)

其他人已经解释了如何配对,所以我在这里关注自己的组合。

如果您想要所有长度的组合,那只是列表的power set,可以通过以下方式计算:

powerset :: [a] -> [[a]]
powerset (x:xs) = let xs' = powerset xs in xs' ++ map (x:) xs'
powerset []     = [[]]

-- powerset [1, 2] === [[],[2],[1],[1,2]]
-- you can take the products:
-- map product $ powerset [1, 2] == [1, 2, 1, 2]

在Haskell中有一个替代的powerset实现,它被认为是一种经典:

import Control.Monad

powerset = filterM (const [True, False])

您可以查看filterM的{​​{3}},了解它的工作方式与上面的其他powerset基本相同。

另一方面,如果您想要拥有特定尺寸的所有组合,您可以执行以下操作:

combsOf :: Int -> [a] -> [[a]]
combsOf n _ | n < 1 = [[]]
combsOf n (x:xs)    = combsOf n xs ++ map (x:) (combsOf (n - 1) xs)
combsOf _ _         = []

-- combsOf 2 [1, 2, 3] === [[2,3],[1,3],[1,2]]

答案 1 :(得分:2)

所以看起来你想要的是列表中的所有产品对:

ghci> :m +Data.List
ghci> [ a * b | a:bs <- tails [2, 3, 5, 587], b <- bs ]
[6,10,1174,15,1761,2935]

但你也想要初始数字:

ghci> [ a * b | a:bs <- tails [2, 3, 5, 587], b <- 1:bs ]
[2,6,10,1174,3,15,1761,5,2935,587]

这使用了列表解析,但这也可以通过常规列表操作来完成:

ghci> concatMap (\a:bs -> a : map (a*) bs) . init $ tails [2, 3, 5, 587]
[2,6,10,1174,3,15,1761,5,2935,587]

后者更容易解释:

  • Data.List.tails生成列表的所有后缀:

    ghci> tails [2, 3, 5, 587]
    [[2,3,5,587],[3,5,587],[5,587],[587],[]]
    
  • Prelude.init删除列表中的最后一个元素。在这里,我使用它来删除空后缀,因为处理会在下一步中导致错误。

    ghci> init [[2,3,5,587],[3,5,587],[5,587],[587],[]]
    [[2,3,5,587],[3,5,587],[5,587],[587]]
    
    ghci> init $ tails [2, 3, 5, 587]
    [[2,3,5,587],[3,5,587],[5,587],[587]]
    
  • Prelude.concatMap在列表的每个元素上运行一个函数,并将结果合并到一个展平列表中。所以

    ghci> concatMap (\a -> replicate a a) [1,2,3]
    [1, 2, 2, 3, 3, 3]
    
  • \(a:bs) -> a : map (a*) bs做了几件事。

    1. 我对我的参数进行模式匹配,断言它匹配一个至少有一个元素的列表(这就是为什么我用init删除了空列表)并将初始元素填入a并且以后的元素到bs
    2. 这将生成一个列表,其与参数a:具有相同的第一个元素,但
    3. 将每个后面的元素乘以amap (a*) bs)。

答案 2 :(得分:1)

您可以使用Data.List.tails获取列表的后缀。 这将为您提供一个列表列表,然后您可以使用以下函数在此列表中执行所需的内部乘法:

prodAll [] = []
prodAll (h:t) = h:(map (* h) $ t)

然后,您可以在每个内部列表上映射此函数并连接结果:

f :: Num a => [a] -> [a]
f = concat . map prodAll . tails