Список понимание: составление списков списков

голоса
9

привет им пытаются сделать функцию в Haskell , которая принимает число а делает его partion использования списков , т.е. для числа 4было бы создать [[1,1,1,1],[1,1,2],[1,3],[2,2],[4]]. Я имел в виду использовать список понимание для этого , где было бы создать список х , а затем создать дополнительные списки с использованием чисел из [1 ... N] (п является номер раздела я хотел бы ) , где сумма сформированного списка будет равна п.

Код, который я создал до сих пор IS-

partions (n:xs) = [[x|x<-[1...n], sum[x]==n]]|xs<-[1..]]

но obiviously он не работает, какие-либо предложения?

Благодарю.

Задан 16/11/2010 в 18:31
источник пользователем
На других языках...                            


4 ответов

голоса
4

Я предлагаю попробовать рекурсии: Для того, чтобы получить разделы п перебирать числа я = 1 до п, и рекурсивно генерировать разделы (Ni), базовый вариант в том, что единственный раздел 1 сам по себе 1, и раздел 0 является пустым списком.

Ответил 16/11/2010 в 18:50
источник пользователем

голоса
3

Как насчет этого...

import Data.List (nub, sort)

parts :: Int -> `Int`
parts 0 = []
parts n = nub $ map sort $ [n] : [x:xs | x <- [1..n`div`2], xs <- parts(n - x)]

Попытка это:

*Main Control.Monad> forM [1..5] (print . parts)
`1`
[[2],[1,1]]
[[3],[1,2],[1,1,1]]
[[4],[1,3],[1,1,2],[1,1,1,1],[2,2]]
[[5],[1,4],[1,1,3],[1,1,1,2],[1,1,1,1,1],[1,2,2],[2,3]]

Я думаю, что это правильно, если не эффективно.

Ответил 17/11/2010 в 01:43
источник пользователем

голоса
2

Я счел полезным определить вспомогательную функцию, partitionsCap, которая не позволить какой - либо из пунктов будет больше заданного значения. Используется рекурсивно, он может быть использован только производить монотонно убывающие результаты , которые вы хотите (т.е. нет , [1,3,1]если у вас уже есть [1,1,3]):

partitions :: Int -> `Int`
partitions n = partitionsCap n n

partitionsCap :: Int -> Int -> `Int`
partitionsCap cap n
    | n < 0  = error "partitions: negative number"
    | n == 0 = [[]]
    | n > 0  = [i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
               where hi = min cap n

В основе алгоритма лежит идея , что, когда разбиение N, вы берете iс nдо 1, и перед именем iв перегородки n-i. Упрощенная:

concat [map (i:) $ partitions (n-i) | i <- [n,n-1..1]]

но не так:

> partitions 3
[[3],[2,1],[1,2],[1,1,1]]

Мы хотим , чтобы [1,2]уйти. Следовательно, нам необходимо ограничить разделы мы Предварение так что они не будут идти выше i:

concat [map (i:) $ partitionsCap i (n-i) | i <- [hi,hi-1..1]]
where hi = min cap n

Теперь, чтобы очистить его: что CONCAT и карта так близко друг к другу моего внимания. Немного предыстории: списочные и список монады являются очень тесно связаны , и concatMap такая же , как >>=с его аргументами перевернутых в списке монады. Таким образом , я задавался вопросом : можно ли те CONCAT и карту как - то превратиться в >>=, и может что - >>=то умаслить свой путь в списке понимание?

В этом случае, ответ да :-)

[i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
where hi = min cap n
Ответил 17/11/2010 в 04:45
источник пользователем

голоса
2

Я немного ржавый с Haskell, но, возможно, следующий код может направить вас, чтобы найти решение.

parts :: Int -> Int -> `Int`
parts 0 p = [[]]
parts x p = [(y:ys) | y <-[p..x], ys <- (parts (x - y) y)]

И тогда вы должны вызвать части с й = п и р = 1.

РЕДАКТИРОВАТЬ

Я установил базовый случай, когда х равен 0, чтобы вернуть список с одним пунктом, в том, что элемент пустой список. Теперь он работает отлично :)

Ответил 16/11/2010 в 18:56
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more