Menu Close

Reparto de escaños por la ley d’Hont

El sistema D’Hondt es una fórmula creada por Victor d’Hondt, que permite obtener el número de cargos electos asignados a las candidaturas, en proporción a los votos conseguidos.

Tras el recuento de los votos, se calcula una serie de divisores para cada partido. La fórmula de los divisores es V/N, donde V representa el número total de votos recibidos por el partido, y N representa cada uno de los números enteros desde 1 hasta el número de cargos electos de la circunscripción objeto de escrutinio. Una vez realizadas las divisiones de los votos de cada partido por cada uno de los divisores desde 1 hasta N, la asignación de cargos electos se hace ordenando los cocientes de las divisiones de mayor a menor y asignando a cada uno un escaño hasta que éstos se agoten

Definir la función

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

tal que (reparto n vs) es la lista de los pares formados por los números de los partidos y el número de escaño que les corresponden al repartir n escaños en función de la lista de sus votos. Por ejemplo,

   ghci> reparto 7 [340000,280000,160000,60000,15000]
   [(1,3),(2,3),(3,1)]
   ghci> reparto 21 [391000,311000,184000,73000,27000,12000,2000]
   [(1,9),(2,7),(3,4),(4,1)]

es decir, en el primer ejemplo,

  • al 1º partido (que obtuvo 340000 votos) le corresponden 3 escaños,
  • al 2º partido (que obtuvo 280000 votos) le corresponden 3 escaños,
  • al 3º partido (que obtuvo 160000 votos) le corresponden 1 escaño.

Soluciones

import Data.List (sort, group)
 
-- Para los ejemplos que siguen, se usará la siguiente ditribución de
-- votos entre 5 partidos.
ejVotos :: [Int]
ejVotos = [340000,280000,160000,60000,15000]
 
-- 1ª solución
-- ===========
 
reparto :: Int -> [Int] -> [(Int,Int)]
reparto n vs = 
  [(x,1 + length xs) | (x:xs) <- group (sort (repartoAux n vs))] 
 
-- (repartoAux n vs) es el número de los partidos, cuyos votos son vs, que
-- obtienen los n escaños. Por ejemplo,
--    ghci> repartoAux 7 ejVotos
--    [1,2,1,3,2,1,2]
repartoAux :: Int -> [Int] -> [Int]
repartoAux n vs = map snd (repartoAux' n vs)
 
-- (repartoAux' n vs) es la lista formada por los n restos mayores
-- correspondientes a la lista de votos vs. Por ejemplo,
--    ghci> repartoAux' 7 ejVotos
--    [(340000,1),(280000,2),(170000,1),(160000,3),(140000,2),(113333,1),
--     (93333,2)]
repartoAux' :: Int -> [Int] -> [(Int,Int)]
repartoAux' n vs = 
  take n (reverse (sort (concatMap (restos n) (votosPartidos vs))))
 
-- (votosPartidos vs) es la lista con los pares formados por los votos y
-- el número de cada partido. Por ejemplo, 
--    ghci> votosPartidos ejVotos
--    [(340000,1),(280000,2),(160000,3),(60000,4),(15000,5)]
votosPartidos :: [Int] -> [(Int,Int)]
votosPartidos vs = zip vs [1..]
 
-- (restos n (x,i)) es la lista obtenidas dividiendo n entre 1, 2,..., n.
-- Por ejemplo, 
--    ghci> restos 5 (340000,1)
--    [(340000,1),(170000,1),(113333,1),(85000,1),(68000,1)]
restos :: Int -> (Int,Int) -> [(Int,Int)]
restos n (x,i) = [(x `div` k,i) | k <- [1..n]]
 
-- 2ª solución
-- ===========
 
reparto2 :: Int -> [Int] -> [(Int,Int)]
reparto2 n xs = 
  ( map (\x -> (head x, length x))  
  . group  
  . sort  
  . map snd  
  . take n  
  . reverse  
  . sort
  ) [(x `div` i, p) | (x,p) <- zip xs [1..], i <- [1..n]]

Otras soluciones

  • Se pueden escribir otras soluciones en los comentarios.
  • El código se debe escribir entre una línea con <pre lang="haskell"> y otra con </pre>
Medio

3 soluciones de “Reparto de escaños por la ley d’Hont

  1. anthormol
    import Data.List
     
    reparto :: Int -> [Int] -> [(Int,Int)]
    reparto n xs =
      aux n
          [(y,x) | (x,y) <- (reverse (sort [ (div x y, p)
                                           | (x,p) <- zip xs [1..],
                                             y <- [1..n]]))]
          [(p,0) | p <- [1..n]]
      where aux 0 _  ys     = filter (x -> snd x /= 0) ys
            aux _ [] ys     = filter (x -> snd x /= 0) ys
            aux n (x:xs) ys = aux (n-1) xs (map (f (fst x)) ys)
            f x (p,q) | x == p    = (p,q+1)
                      | otherwise = (p,q)
  2. Enrique Zubiría
    import Data.List
     
    reparto :: Int -> [Int] -> [(Int,Int)]
    reparto n vs =
      [ (p+1, e) | p <- [0..nPartidos-1],
                   let e = length $ filter (c -> snd c == p) cocientes,
                   e > 0]
      where nPartidos = length vs
            cocientes = take n ( reverse
                               $ sort
                               $ concat [[ (div (vs!!p) c, p)
                                         | c <- [1..n]]
                                        | p <- [0..nPartidos-1]])
  3. javjimord
    import Data.List 
     
    reparto :: Int -> [Int] -> [(Int,Int)]
    reparto n vs = zip [1..] (escaños n vs)
     
    escaños :: Int -> [Int] -> [Int]
    escaños n vs = [ length (filter (`elem` cocientes n v) (asignacion n vs))
                   | v <- vs]
     
    cocientes :: Int -> Int -> [Int]
    cocientes n v  = [v `div` n' | n' <- [1..n]] 
     
    listaCocientes :: Int -> [Int] -> [Int]
    listaCocientes n vs = reverse (sort (concat (map (cocientes n) vs)))
     
    asignacion :: Int -> [Int] -> [Int]
    asignacion n vs = map snd (zip (replicate n 1) (listaCocientes n vs))

Leave a Reply

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.