Я новичок в Haskell.
Как сгенерировать список списков, содержащий простые множители следующих целых чисел?
Теперь я знаю только, как сгенерировать простые числа:
primes = map head $ iterate (\(x:xs) -> [y | y<-xs, y `mod` x /= 0 ]) [2..]
Я новичок в Haskell.
Как сгенерировать список списков, содержащий простые множители следующих целых чисел?
Теперь я знаю только, как сгенерировать простые числа:
primes = map head $ iterate (\(x:xs) -> [y | y<-xs, y `mod` x /= 0 ]) [2..]
Простой подход для определения простых множителей n
равен
d
в [2..n-1]
d : primeFactors(div n d)
n
(так как n
является простым)Код:
prime_factors :: Int -> [Int]
prime_factors 1 = []
prime_factors n
| factors == [] = [n]
| otherwise = factors ++ prime_factors (n `div` (head factors))
where factors = take 1 $ filter (\x -> (n `mod` x) == 0) [2 .. n-1]
Это, очевидно, может использовать большую оптимизацию (поиск только от 2 до sqrt (N), кеширование простых чисел, найденных до сих пор, и вычисление деления только для этих и т.д.)
UPDATE
Немного измененная версия с использованием case (как предложено @user5402):
prime_factors n =
case factors of
[] -> [n]
_ -> factors ++ prime_factors (n `div` (head factors))
where factors = take 1 $ filter (\x -> (n `mod` x) == 0) [2 .. n-1]
До тех пор, пока дивиденд m
2,
n
из простых чисел.m
на n
в то время как делится.n
из простых чисел и перейдите к 2.Список всех используемых делителей - это простые множители оригинала m
.
Код:
-- | prime factors
--
-- >>> factors 13
-- [13]
-- >>> factors 16
-- [2,2,2,2]
-- >>> factors 60
-- [2,2,3,5]
--
factors :: Int -> [Int]
factors m = f m (head primes) (tail primes) where
f m n ns
| m < 2 = []
| m `mod` n == 0 = n : f (m `div` n) n ns
| otherwise = f m (head ns) (tail ns)
-- | primes
--
-- >>> take 10 primes
-- [2,3,5,7,11,13,17,19,23,29]
--
primes :: [Int]
primes = f [2..] where f (p : ns) = p : f [n | n <- ns, n `mod` p /= 0]
Update:
Этот код замены повышает производительность, избегая ненужных оценок:
factors m = f m (head primes) (tail primes) where
f m n ns
| m < 2 = []
| m < n ^ 2 = [m] -- stop early
| m `mod` n == 0 = n : f (m `div` n) n ns
| otherwise = f m (head ns) (tail ns)
primes
также можно ускорить, как указано в комментарий Will Ness:
primes = 2 : filter (\n-> head (factors n) == n) [3,5..]
Это хорошо продуманная и простая в понимании реализация, в которой isPrime
и primes
определены рекурсивно, а primes
будет кэшироваться по умолчанию. primeFactors
определение - это просто правильное использование primes
, результат будет содержать непрерывные дублированные числа, эта функция позволяет легко подсчитать количество каждого фактора с помощью (map (head &&& length) . group)
и легко его уникально через (map head . group)
:
isPrime :: Int -> Bool
primes :: [Int]
isPrime n | n < 2 = False
isPrime n = all (\p -> n `mod` p /= 0) . takeWhile ((<= n) . (^ 2)) $ primes
primes = 2 : filter isPrime [3..]
primeFactors :: Int -> [Int]
primeFactors n = iter n primes where
iter n (p:_) | n < p^2 = [n | n > 1]
iter n [email protected](p:ps') =
let (d, r) = n `divMod` p
in if r == 0 then p : iter d ps else iter n ps'
И использование:
> import Data.List
> import Control.Arrow
> primeFactors 12312
[2,2,2,3,3,3,3,19]
> (map (head &&& length) . group) (primeFactors 12312)
[(2,3),(3,4),(19,1)]
> (map head . group) (primeFactors 12312)
[2,3,19]
Haskell позволяет создавать бесконечные списки, которые являются взаимно рекурсивными. Пусть это выгодно.
Сначала создайте вспомогательную функцию, которая как можно больше делит число на другое. Нам понадобится, когда мы найдем фактор, чтобы полностью исключить его из числа.
import Data.Maybe (mapMaybe)
-- Divide the first argument as many times as possible by the second one.
divFully :: Integer -> Integer -> Integer
divFully n q | n `mod` q == 0 = divFully (n `div` q) q
| otherwise = n
Далее, предполагая, что у нас есть список всех простых чисел, мы можем легко найти множители чисел, разделив его на все простые числа, меньшие квадратного корня из числа, и если число делится, отметив простое число.
-- | A lazy infinite list of non-trivial factors of all numbers.
factors :: [(Integer, [Integer])]
factors = (1, []) : (2, [2]) : map (\n -> (n, divisors primes n)) [3..]
where
divisors :: [Integer] -> Integer -> [Integer]
divisors _ 1 = [] -- no more divisors
divisors (p:ps) n
| p^2 > n = [n] -- no more divisors, `n` must be prime
| n' < n = p : divisors ps n' -- divides
| otherwise = divisors ps n' -- doesn't divide
where
n' = divFully n p
И наоборот, когда у нас есть список всех факторов чисел, легко найти простые числа: они точно такие числа, единственным простым фактором которых является само число.
-- | A lazy infinite list of primes.
primes :: [Integer]
primes = mapMaybe isPrime factors
where
-- | A number is prime if it only prime factor is the number itself.
isPrime (n, [p]) | n == p = Just p
isPrime _ = Nothing
Фокус в том, что мы начинаем список факторов вручную, и чтобы определить список простых факторов числа, нам нужны только числа меньше, чем его квадратный корень. Посмотрим, что произойдет, когда мы немного перечислим список факторов, и мы пытаемся вычислить список факторов из 3. Мы потребляем список простых чисел, беря 2 (которые можно вычислить из того, что мы дали вручную). Мы видим, что он не делит 3 и что, так как он больше квадратного корня из 3, то нет более возможных делителей 3. Поэтому список факторов для 3 равен [3]
. Из этого можно вычислить, что 3 - другое простое. Etc.
Я просто работал над этой проблемой. Здесь мое решение.
Две вспомогательные функции:
factors n = [x | x <- [1..n], mod n x == 0]
isPrime n = factors n == [1,n]
Затем, используя понимание списка, чтобы получить все основные факторы и сколько их.
prime_factors num = [(last $ takeWhile (\n -> (x^n) `elem` (factors num)) [1..], x) | x <- filter isPrime $ factors num]
где
x <- filter isPrime $ factors num
говорит мне, какие простые коэффициенты имеют заданное число, а
last $ takeWhile (\n -> (x^n) `elem` (factors num)) [1..]
говорит мне, сколько этого фактора.
<сильные > Примеры
> prime_factors 36 -- 36 = 4 * 9
[(2,2),(2,3)]
> prime_factors 1800 -- 1800 = 8 * 9 * 25
[(3,2),(2,3),(2,5)]
более элегантный код , используйте 2 и нечетные числа, чтобы разделить число.
factors' :: Integral t => t -> [t]
factors' n
| n < 0 = factors' (-n)
| n > 0 = if 1 == n
then []
else let fac = mfac n 2 in fac : factors' (n 'div' fac)
where mfac m x
| rem m x == 0 = x
| x * x > m = m
| otherwise = mfac m (if odd x then x + 2 else x + 1)
Здесь моя версия. Не так кратко, как другие, но я думаю, что это очень читабельно и легко понять.
import Data.List
factor :: Int -> [Int]
factor n
| n <= 1 = []
| even n = 2 : factor(div n 2)
| otherwise =
let root = floor $ sqrt $ fromIntegral n
in
case find ((==) 0 . mod n) [3, 5.. root] of
Nothing -> [n]
Just fac -> fac : factor(div n fac)