Факторизация простых чисел с использованием понимания списка

Я хочу найти все простые множители заданного числа, используя только метод понимания списка и/или . (оператор композиции функций) в Haskell. Я специально хочу избежать рекурсивного решения.

Например, pfactors 120 должен производить [2,2,2,3,5] выходных данных.

Я старался:

pfactors n = [p | p <- [2..n], n `mod` p == 0, [d | d <- [1..p], p `mod` d == 0] == [1,p]]

Но когда я вызываю pfactors 120, результатом будет [2,3,5], а не все простые множители.


person sasas    schedule 02.06.2014    source источник
comment
факторы n = [p | p ‹- [2..n], n mod p == 0, [d | d ‹- [1..p], p mod d == 0] == [1,p]]   -  person sasas    schedule 03.06.2014
comment
Но когда я называю pfactors 120, результатом будет [2,3,5], а не все простые множители.   -  person sasas    schedule 03.06.2014
comment
он уже поставлен.   -  person sasas    schedule 03.06.2014
comment
Не то, что вы пробовали...   -  person ThreeFx    schedule 03.06.2014
comment
у вас есть список простых чисел?   -  person Sassa NF    schedule 03.06.2014
comment
Вы получаете список уникальных простых множителей числа n, но, как ясно показывает ваш пример, некоторые множители встречаются более одного раза, и даже если вы перечислили значения несколько раз , вы бы не знали, сколько раз вам нужно сделать это, чтобы получить все множественные факторы.   -  person didierc    schedule 03.06.2014
comment
Не понимаю, почему за этот вопрос проголосовали...   -  person luqui    schedule 03.06.2014
comment
Потому что проблема неразрешима.   -  person didierc    schedule 03.06.2014
comment
Да, Дидьерек, верно. Некоторые факторы встречаются более одного раза. Но должно быть решение. Как я могу перечислить все несколько факторов с пониманием списка?   -  person sasas    schedule 03.06.2014
comment
Да, я тоже не понимаю @luqui   -  person sasas    schedule 03.06.2014
comment
Вероятно, из-за изначального отсутствия кода из ОП.   -  person Sean Perry    schedule 03.06.2014
comment
Я так думаю, я здесь новичок, поэтому не заметил.   -  person sasas    schedule 03.06.2014


Ответы (1)


Вот как бы я это сделал:

pfactors :: Integer -> [Integer]
pfactors n = [ p
             | p <- [2..n]                                  -- Possible factors
             , [d | d <- [1..p], p `mod` d == 0] == [1,p]   -- Are prime 
             , _ <- [ p | i <- [1..n], n `mod` p^i == 0] ]  -- Divisible powers

По сути, это то решение, которое у вас есть, но разница в том, что в конце есть дополнительное понимание списка, которое содержит столько элементов, сколько p делит на n.

Отказ от ответственности В реальности я бы так не поступил.

EDIT Я чувствовал себя грязным, когда писал выше, поэтому для справки, это что-то более близкое к тому, что я бы написал:

pfactors' :: Int -> [Int]
pfactors' = unfoldr firstFactor
  where
    firstFactor n =
        listToMaybe [(f, n `div` f)
                    | f <- [2..n]
                    , n `mod` f == 0]

Зависимости: Data.List (unfoldr), Data.Maybe (listToMaybe)

person amnn    schedule 02.06.2014
comment
Хорошо, я исправлен, но разве вы не должны фильтровать, чтобы оставить только самые высокие степени каждого p? - person didierc; 03.06.2014
comment
Отлично @asQuirrel. Это мой ответ. Большое спасибо! - person sasas; 03.06.2014
comment
@didierc, я в это не верю. Что я здесь делаю, так это сохраняю все степени p, которые делят n (по определению, это будут наименьшие степени). - person amnn; 03.06.2014
comment
Да, все силы, но, строго говоря, не должны ли вы возвращать только самые высокие? (Я говорю строго, потому что их всегда можно потом отфильтровать, так что ваш ответ в порядке). - person didierc; 03.06.2014
comment
Я согласен с вами @asQuirrel. Рекурсивное решение является лучшим. Но мне было интересно, возможно ли это с помощью этого метода. С тобой все возможно :) Спасибо. - person sasas; 03.06.2014
comment
@didierc, я все равно не понимаю вас, если вы говорите о значении для p, оно сначала проверяется на простоту, если вы говорите о последней части (то, что я добавил), то значения отбрасываются, все нас на самом деле интересовало количество степеней. - person amnn; 03.06.2014
comment
Аааа, хорошо, я не понял ваш код. Очень умно. - person didierc; 03.06.2014
comment
очень хороший listToMaybe трюк!.. Хотя ваша формулировка неэффективна; должно быть factors n = unfoldr g (2,n) where g (d, n) = listToMaybe [(x, (x, div n x)) | n > 1, x <- [d..isqrt n]++[n], rem n x == 0]. Подробнее здесь. :) - person Will Ness; 03.06.2014
comment
Очень хорошо, это решение, к которому я стремился :) - person amnn; 03.06.2014
comment
он по-прежнему неоптимален: он проверяет по всем числам, а не только по простым числам (предварительный расчет простых чисел требует времени, но стоит того, когда выполняется несколько вызовов factors). ср. haskell.org/haskellwiki/ . Но, по крайней мере, недостаток не квадратичен... - person Will Ness; 03.06.2014