给定长度为x
的列表列表,其中所有子列表具有相同的长度y
,输出长度为y^x
的{{1}}列表,每个列表包含一个项目子列表。
示例(x
,x = 3
):
y = 2
输出([ [1, 2], [3, 4], [5, 6] ]
不同的输出):
2^3 == 8
红宝石
我编写了实际代码来执行此任务,但在Ruby中,因为它是我最熟悉的语言。
[ [1, 3, 5], [1, 4, 5], [1, 3, 6], [1, 4, 6],
[2, 3, 5], [2, 4, 5], [2, 3, 6], [2, 4, 6] ]
类型
输入是包含类型a的项目的列表列表,输出也是如此。
def all_combinations(lst)
lst.inject {|acc, new| acc.product(new).map(&:flatten) }
end
笛卡尔积,扁平化和折叠
查看我的Ruby解决方案让我觉得充分利用这些功能可能足以解决问题。问题是,虽然笛卡尔积输出了一个元组列表,但我需要一个列表列表。
答案 0 :(得分:12)
注意:这篇文章是用文字Haskell编写的。安全吧 * .lhs并将其加载到GHCi中。
> -- remove this line if you don't have QuickCheck installed
> import Test.QuickCheck
让我们从allProduct
的简单变体开始:
> allProductFirst :: [[a]] -> [[a]]
> allProductFirst [] = [[]]
> allProductFirst (x:xs) =
现在x
本身又是一个列表。让我们说allProduct xs
会给我们其他列表的产品。
> let rest = allProductFirst xs
我们需要做什么?我们需要为x
中的每个元素创建一个新列表,并将它们连接在一起:
> in concatMap (\k -> map (k:) rest) x
请注意,此变体不是100%正确,因为allProduct []
是[[]]
。
如果我们要使用Monad
的{{1}}实例,这会是什么样子?
[]
表示法do
我们想要采用> allProduct' :: [[a]] -> [[a]]
> allProduct' [] = [[]]
> allProduct' (x:xs) = do
x
并将其列入我们列表可能具有的所有可能后缀:
> elementOfX <- x
这意味着我们基本上会评估列表monad中的每个操作。但是有一个功能:> rest <- allProduct' xs
> return $ elementOfX : rest
。如果我们使用sequence :: Monad m => [m a] -> m [a]
,则其类型可以专门用于m ~ []
。
sequence :: [[a]] -> [[a]]
我们最终得到了我们的最后一个变体:
sequence
我们使用QuickCheck测试它可能与> allProduct :: [[a]] -> [[a]]
> allProduct = sequence
相同
和allProductFirst
:
allProduct'
在GHCi中使用> main :: IO ()
> main = do
> quickCheck $
> forAll (choose (1,8)) $ \n -> -- number of lists
> forAll (choose (1,4)) $ \s -> -- number of elements per list
> forAll (vectorOf n $ vector s) $ \xs ->
> allProduct' xs === allProduct (xs :: [[Integer]]) .&.
> allProductFirst xs === allProduct xs
,:main
或编译并运行您的程序
最终应该通过100次测试。