【问题标题】:All possible sublists of a list列表的所有可能子列表
【发布时间】:2012-11-18 18:34:23
【问题描述】:

我需要编写一个函数来生成一个列表,该列表包含列表的所有可能子列表的列表。所以类型必须是:

partitions :: [a] -> [[[a]]]

它应该给出:

分区 [1..4] = [[[1],[2],[3],[4]], [[1,2],[3],[4]], [[1],[2,3],[4]], [[1,2,3],[4]], [[1],[2],[3,4]], [[1, 2],[3,4]], [[1],[2,3,4]], [[1,2,3,4]]]

我认为列表理解是最好的方法。到目前为止,我有:

partitions :: [a]  -> [[[a]]]
partitions (x:xs) = foldr insert [[]] (x:xs)
   where insert ys zs = ys:x:zs

如您所料,这会引发类型错误,但我不知道如何修复它。我觉得我遗漏了一些明显的东西,任何帮助将不胜感激。

【问题讨论】:

  • 我想也许您想要 powerset (filterM (const [True, False])),但您的定义略有不同。您想要列表的所有可能分区吗?
  • 你认为insert的类型是什么?我认为insert :: a -> [[[a]]] -> [[[a]]]。你认为insert 什么时候使用?事实上,它在foldr 的列表递归的每一步 中使用,因此您的代码似乎试图给出生成大量x 副本的答案。使用foldr 的想法很好:只要考虑一下[] 的分区是什么,以及如何计算非空列表(例如[1,2,3,4])的分区,给定它的尾部分区([2,3,4])。对于后者,请考虑如何将头元素(此处为1)添加到每个尾分区。列表组合可能确实有帮助。
  • 列表的每个副本的划分与[1..n-1]上的所有特征函数对应(对于列表n的长度)。您可以通过replicateM (pred n) [True,False](为什么?),然后zipWith 一个适当的组合函数和2^(n-1) 原始列表的副本生成这些。 (绕过显式创建特征函数的解决方案的加分项。)
  • Fixnum,看起来真的很复杂。您确定这里真的需要这种复杂性吗?
  • 您确定不想将[[1,3],[2,4]] 包含在结果中吗?那也是隔断! (至少在数学意义上)

标签: list haskell


【解决方案1】:

我将从直接递归开始。分解一下,较长列表中的第一个元素有什么可能性?

  1. 它可以是其中一个分区列表的唯一元素。
  2. 它可以是具有多个元素的分区列表的一部分。

从您的示例来看,您似乎希望保持原始元素有序,因此每个分区的成员只能是连续的子列表,这使得它更容易一些。

所以我们可以开始了

partitions :: [a] -> [[[a]]]
partitions [] = [[]]    -- only one partition of an empty list, an empty partition
partitions (x:xs) = [[x]:part | part <- partitions xs] ++ [(x:ys):yss | (ys:yss) <- partitions xs]

产生

*Partitions> partitions [1,2,3,4]
[[[1],[2],[3],[4]],[[1],[2],[3,4]],[[1],[2,3],[4]],[[1],[2,3,4]],[[1,2],[3],[4]],[[1,2],[3,4]],[[1,2,3],[4]],[[1,2,3,4]]]

不是所需的顺序。如果这很重要,我们必须重写。期望的顺序直接连续列出第一个元素的两个选项,所以我们可以写它

partitions (x:xs) = partitions xs >>= \zs -> case zs of
                                               [] -> [[[x]]]
                                               (ys:yss) -> [[x]:ys:yss, (x:ys):yss]

我们需要明确区分空分区(在递归结束时)和非空分区的情况,在上面是通过绑定到模式(ys:yss) 隐式完成的。这会产生所需的顺序

*Partitions> partitions [1,2,3,4]
[[[1],[2],[3],[4]],[[1,2],[3],[4]],[[1],[2,3],[4]],[[1,2,3],[4]],[[1],[2],[3,4]],[[1,2],[3,4]],[[1],[2,3,4]],[[1,2,3,4]]]

使用列表 monad 的绑定 (&gt;&gt;=)flip concatMap 的事实,版本

partitions (x:xs) = concatMap insert (partitions xs)
  where
    insert [] = [[[x]]]
    insert (ys:yss) = [[x]:ys:yss, (x:ys):yss]

可能更具可读性。

【讨论】:

  • 这里的顺序无关紧要。谢谢你的帮助,我应该可以用你给我的东西以折叠形式重写它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多