【问题标题】:How to create all possible combinations of these two lists?如何创建这两个列表的所有可能组合?
【发布时间】:2019-10-15 04:34:06
【问题描述】:

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

例如

给定两个列表:[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]

【问题讨论】:

  • 在您的示例中,数字是恒定的,因此您可以执行以下操作:[ [(1,x),(2,y),(3,z)] | x &lt;- [True, False], y &lt;- [True, False], z &lt;- [True, False] ]
  • 在这种情况下,数字是可变的。唯一不变的是[True, False]
  • 我想我说错了,我的意思是在示例中它始终是1,2,3

标签: list haskell combinations combinatorics


【解决方案1】:

我们可以避免使用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)]]

上述方法不适用于无限列表,尽管我们可以,假设第一个列表包含至少一个元素,稍微修改代码,以生成结果的第一个元素:一个压缩列表中所有元素的列表该项目的第二个列表。我把它留作练习。

【讨论】:

  • 无论你多么聪明,你都无法在无限列表上正确实现这一点。谢谢,康托尔!
  • @luqui 另一方面,应该可以为具有以下属性的无限列表做一些事情:首先我选择(无限)结果列表 2.然后你选择你最喜欢的有限前缀长度 3. 然后我可以证明该长度前缀的所有标签都出现在我的结果列表中的有限索引处。这对于大多数计算来说应该已经足够了——至少是你期望最终完成的那些!
【解决方案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]应该会给你你想要的。

【讨论】:

  • 解决更普遍的问题,然后让你的小问题免费解决原则,呵呵。此外,如果我们内联 dropWhile 和 takeWhile,我们最终会得到与序列等效的 zip 列表理解。 :) 但您可能想要通用代码,用于任意 n...
  • @WillNess 是回答作业问题的好方法,我认为:有用且真实,但您仍然需要思考才能将其还原为原始问题;如果你只是复制/粘贴它,教练会合理地认为你不是自己做的。
  • @amalloy 几年前在 meta 上讨论过关于家庭作业的讨论,当时标签被“烧毁”,据我所知,判决结果是,“只要回答它,不管".我不知道目前的共识是什么。
  • 是的,应该回答问得很好的家庭作业问题。但我认为以留下指纹的方式回答问题并不违背事情的精神。
【解决方案3】:

你想要的输出可以通过定义来产生

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 个值的所有可能函数,无论这些空格和值是什么。

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

edit: 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

【讨论】:

  • 哦,sequence 是我想要的。我不知道该怎么做。不错!
【解决方案4】:

又好又短:

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

或者说不那么无意义,但也许更容易理解:

{-# LANGUAGE TupleSections #-}

traverse (\x -> (x,) <$> [True, False]) [1,2,3]

内部函数((&lt;$&gt; [True, False]) . (,)\x -&gt; (x,) &lt;$&gt; [True, False])获取每个元素,例如1,并将其转换为[(1,True),(1,False)]。如果您将traverse f 视为sequence . fmap f,那么fmap f 部分意味着对列表中的每个事物执行该功能(产生[[(1,True),(1,False)],[(2,True),(2,False)],[(3,True),(3,False)]]),sequence 部分意味着将它们与列表应用程序(模型非确定性)来创建所有可能的组合(产生[[(1,True),(2,True),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,False),(3,False)],[(1,False),(2,True),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,False),(3,False)]])。

【讨论】:

  • sequence [map (x ,) [False, True] | x &lt;- [1,2,3]],然后。 :) 似乎是这样。不错!
  • 它实际上是 (List) Monad 的核心,liftA2 (,) xs ys = join [fmap (x ,) ys | x &lt;- xs](和 xs &lt;|&gt; ys = join [xs, ys])。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 1970-01-01
  • 2022-01-12
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多