如何创建这两个列表的所有可能组合?

时间:2019-10-15 04:34:06

标签: list haskell combinations combinatorics

我想从这两个列表中创建一个所有组合的列表,其中每个组合也是一个列表。

例如

给出两个列表:[1,2,3][True, False]

组合:

[(1, False), (2, False), (3, False)]
[(1, False), (2, False), (3, True )]
[(1, False), (2, True ), (3, False)]
[(1, True ), (2, False), (3, False)]
[(1, False), (2, True ), (3, True )]
[(1, True ), (2, False), (3, True )]
[(1, True ), (2, True ), (3, False)]
[(1, True ), (2, True ), (3, True )]

应该有2^n个组合,其中n是数字的数量。

编辑:

尝试执行以下操作:

[(n, b) | n <- [1,2,3], b <- [True, False]]
(,) <$> [1,2,3] <*> [True, False]

4 个答案:

答案 0 :(得分:3)

我们可以避免使用length,这可能是不安全的,因为列表的长度可以无限。通过使用递归或文件夹模式,我们可以避免这种情况:

{-# LANGUAGE TupleSections #-}

allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = go
    where go [] = [[]]
          go (x:xs) = (:) <$> map (x,) vs <*> go xs

或在单层中使用折叠图案:

allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = foldr (\x -> ((:) <$> map (x,) vs <*>)) [[]]

例如:

Prelude> allComb [False, True] [1,2,3]
[[(1,False),(2,False),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,True),(3,True)],[(1,True),(2,False),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,True),(3,True)]]

以上方法不适用于无限列表,尽管我们可以在给定第一个列表至少包含一个元素的情况下,稍稍更改代码以生成结果的第一个元素:将列表中所有元素压缩的列表该项目的第二个清单。我将其保留为练习。

答案 1 :(得分:2)

可以通过定义来产生所需的输出

foo :: [a] -> [b] -> [[(a, b)]]
foo nums bools =
    map (zip nums) . sequence $ replicate (length nums) bools
  =
    let n = length nums 
    in 
        [ zip nums bs | bs <- sequence $ replicate n bools]

并致电

foo [1,2,3] [False, True]

该呼叫等同于

    let nums = [1,2,3]
        bools = [False, True]
        n = 3
    in 
        [ zip nums bs | bs <- sequence $ replicate n bools]
      =
        [ zip [1,2,3] bs | bs <- sequence $ replicate 3 [False, True]]
      =
        [ zip [1,2,3] (b:bs) | b  <- [False, True]
                             , bs <- sequence $ replicate 2 [False, True]]
      =
        [ zip [1,2,3] (b:c:bs) | b  <- [False, True]
                               , c  <- [False, True]
                               , bs <- sequence $ replicate 1 [False, True]]
      =
        [ zip [1,2,3] (b:c:d:bs) | b  <- [False, True]
                                 , c  <- [False, True]
                                 , d  <- [False, True]
                                 , bs <- sequence $ replicate 0 [False, True] ]
      =
        [ zip [1,2,3] (b:c:d:bs) | b  <- [False, True]
                                 , c  <- [False, True]
                                 , d  <- [False, True]
                                 , bs <- sequence [] ]
      =
        [ zip [1,2,3] (b:c:d:bs) | b  <- [False, True]
                                 , c  <- [False, True]
                                 , d  <- [False, True]
                                 , bs <- [[]] ]
      =
        [ zip [1,2,3] (b:c:d:[]) | b  <- [False, True]
                                 , c  <- [False, True]
                                 , d  <- [False, True] ]

        [ zip [1,2,3] [b,c,d]    | b  <- [False, True]
                                 , c  <- [False, True]
                                 , d  <- [False, True] ]

如果对最后一个表达式求值,我们也会得到相同的结果。

用两个可用值的每种可能组合填充三个空格,就像具有从3个空格到2个值的所有可能函数一样,无论这些空格和值是什么。

数学家将此函数写为 2 3 ,实际上,我们得到了2^3 = 8输出。

编辑: sequence ... replicate组合实际上只是在重新实现另一个内置replicateM

foo ns bs = map (zip ns) (replicateM (length ns) bs)

因为replicateM n asequence (replicate n a)相似,但实际上并未建立中间列表。

对于迷来说,我们可以拥有

foo ns    =  map (zip ns) . replicateM (length ns)
          =  (.) ((map . zip) ns) ((replicateM . length) ns)
          =  ((.) . map . zip <*> replicateM . length)   ns

foo       =  (.) . map . zip <*> replicateM . length

答案 2 :(得分:2)

这不是最直接或最有效的答案。

但是使用How to generate a list of all possible strings from shortest to longest中的技术,我们可以生成所有可能的布尔序列的列表。我们采用与第二个列表相同的长度,然后用该列表压缩它们。

allBoolPermutations :: Int -> [[Bool]]
allBoolPermutations n = takeWhile (\l -> length l == n) 
                      $ dropWhile (\l -> length l < n) 
                      $ allBools
  where
    allBools = [ c : s | s <- []:allBools, c <- [True, False]] 


zipWithBoolPermutations :: [a] -> [[(a, Bool)]]
zipWithBoolPermutations someList = map (zip someList) 
                                       (allBoolPermutations (length someList))

然后zipWithBoolPermutations [1,2,3]应该给您您想要的东西。

答案 3 :(得分:2)

简短简短:

setup(name="<module name>",
        version="0.1",
        packages=['<package name if any or ignore>'],
        install_requires=['pandas==0.25.1']
    )

或更没有意义,但也许更容易理解:

traverse ((<$> [True, False]) . (,)) [1,2,3]

内部函数({-# LANGUAGE TupleSections #-} traverse (\x -> (x,) <$> [True, False]) [1,2,3] (<$> [True, False]) . (,))采用诸如\x -> (x,) <$> [True, False]之类的每个元素,并将其转换为1。如果您将[(1,True),(1,False)]视为traverse f,则sequence . fmap f部分意味着对列表中的每一件事都起作用(产生fmap f),而{{1} }部分意味着将它们与List应用程序(用于模拟非确定性模型)组合以创建所有可能的组合(产生[[(1,True),(1,False)],[(2,True),(2,False)],[(3,True),(3,False)]])。