Ir al contenido principal

Parejas de números y divisores

Definir la función

divisoresHasta :: Int -> [(Int,Int)]

tal que (divisoresHasta n) es la lista de los pares (a,b) tales que a es un número entre 2 y n y b es un divisor propio de a. Por ejemplo,

λ> divisoresHasta 6
[(2,1),(3,1),(4,1),(5,1),(6,1),(4,2),(6,2),(6,3)]
λ> divisoresHasta 8
[(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(4,2),(6,2),(8,2),(6,3),(8,4)]
λ> length (divisoresHasta 1234567)
16272448

Soluciones

import Data.List (sort, sortBy)
import Data.Ord (comparing)
import Data.Tuple (swap)

-- 1ª definición
-- =============

divisoresHasta1 :: Integer -> [(Integer,Integer)]
divisoresHasta1 n =
    ordena (concat [[(a,b) | b <- divisoresPropios a] | a <- [2..n]])
    where intercambia (x,y) = (y,x)
          ordena ps = [intercambia p | p <- sort (map intercambia ps)]

divisoresPropios :: Integer -> [Integer]
divisoresPropios n = [x | x <- [1..n-1], n `mod` x == 0]

-- 2ª definición
-- =============

divisoresHasta2 :: Integer -> [(Integer,Integer)]
divisoresHasta2 n =
    ordena (concat [[(a,b) | b <- divisoresPropios a] | a <- [2..n]])
    where ordena           = sortBy comp
          comp (x,y) (u,v) = compare (y,x) (v,u)

-- 3ª definición
-- =============

divisoresHasta3 :: Integer -> [(Integer,Integer)]
divisoresHasta3 n =
    ordena (concat [[(a,b) | b <- divisoresPropios a] | a <- [2..n]])
    where ordena = sortBy (comparing swap)

-- 4ª definición
-- =============

divisoresHasta4 :: Integer -> [(Integer,Integer)]
divisoresHasta4 n = [(a,b) | b <- [1..n], a <- [b+b, b+b+b..n]]

-- Comparaciones de eficiencia
-- ===========================

-- λ> length (divisoresHasta1 3000)
-- 21496
-- (6.14 secs, 967750416 bytes)
--
-- λ> length (divisoresHasta2 3000)
-- 21496
-- (6.27 secs, 993527816 bytes)
--
-- λ> length (divisoresHasta3 3000)
-- 21496
-- (6.14 secs, 991442120 bytes)
--
-- λ> length (divisoresHasta4 3000)
-- 21496
-- (0.02 secs, 6224480 bytes)