所有可能的子列表都是成对的

时间:2011-05-07 10:52:45

标签: haskell

不确定如何正确地说出来,所以请耐心等待!

给定一个列表[1,2,3,4]我想要一个列表元组列表,如下所示:[([1],[2,3,4]),([1,2],[ 3,4]),([1,2,3],[4])。

问题的B部分也是在子列表中获得所有可能的排序。所以在第一个元组的情况下,我希望2 3 4按顺序243,324,432,423 ......

是的,我喜欢非决定论。

4 个答案:

答案 0 :(得分:4)

import Data.List (inits, tails, permutations)
import Control.Arrow (first, second)

parta :: [a] -> [([a], [a])]
parta [] = []
parta xs = init . tail $ zip (inits xs) (tails xs)

对于b部分,我不确定您是想要[([1],[2,3,4]), ([1],[3,4,2]), ...]还是[([1],[[2,3,4],[3,4,2],...]), ...]。如果是后者,那么

partb :: [a] -> [([a], [[a]])]
partb = map (second permutations) . parta

编辑:哦,但你想要前者。在那种情况下

partb :: [a] -> [([a], [a])]
partb = map (uncurry zip . first repeat . second permutations) . parta

最终编辑:由于我已经使用了Control.Arrow中的一些函数,我会注意到zip (inits xs) (tails xs)也可以写成(inits &&& tails) xs,但我不是确定它更清楚。

答案 1 :(得分:3)

A部分:使用非决定论monad! (列表monad)

第1步:找到一个合适的方法,将列表拆分为两个列表的元组。

Hoogling [a] -> ([a], [a])我们找到splitAt :: Int -> [a] -> ([a],[a])

import Data.List (splitAt, permutations) -- we'll need to permute for part B

第2步:将其写入一个索引。

splitPair xs = splitAt 1 xs

第3步:让许多索引无法确定地工作。

splitPairs xs = do index <- [1..length xs-1]
                   return $ splitAt index xs

了解单选功能可以轻松转换为非确定性选择功能吗? (这与列表理解一样容易编写:)

splitPairs' xs = [splitAt i xs | i <- [1..length xs-1]]

B部分:再使用非决定论monad!

splitPairsPerms xs = do (ys, zs) <- splitPairs xs
                        ys' <- permutations ys
                        zs' <- permutations zs
                        return $ (ys', zs')

进一步的想法

list monad非常适合编写简单函数并将它们转换为非确定性函数。然而,这种方法并不总是最有效的。在我的示例中,我使用了length xssplitAt i xs之类的操作,它们必须遍历列表的长度才能执行任务(好吧,splitAt只需要遍历索引i,它平均是列表长度的一半,所以数量级相同)。如果性能很重要,那么转换为序列可能是明智的。

答案 2 :(得分:2)

在第一种情况下,您只需将列表拆分为两个。第一个将包含输入,第二个将最初为空。比从第一个元素中取一个元素,然后将它放在第二个元素中,直到第一个元素为空。

magic x = magic' x []
    where 
        magic' [] y = [[[], y]]
        magic' (x:xs) y = [[reverse y, (x:xs)]] ++ magic' xs (x:y)

下一个问题:它只是元素的简单排列。

perm x = perm' x [] []
    where
        perm' [] [] prefix = [prefix]
        perm' [] rest prefix = []
        perm' (x:xs) rest prefix =
            perm' (xs++rest) [] (x:prefix) ++
            perm' xs (x:rest) prefix

答案 3 :(得分:1)

我最喜欢丹的答案,因为我认为这是最有启发性的。但是,如果您担心splitPair的效率,那么我认为这个相当直接的定义可以正常工作:

splitPair :: [a] -> [([a],[a])]
splitPair []       = ([],[]) : []
splitPair a@(x:xs) = ([],a)  : map (\(u,v)->(x:u,v)) (splitPair xs)

这个定义与原始问题陈述有所不同,它返回第一个或最后一个列表为空的对。这与大多数列表函数的定义更为一致,例如tailsinits

> splitPair [1,2,3,4]
[([],[1,2,3,4]),([1],[2,3,4]),([1,2],[3,4]),([1,2,3],[4]),([1,2,3,4],[])]