Last active
October 6, 2015 18:05
-
-
Save mcsf/2d43ef5c33198522b22f to your computer and use it in GitHub Desktop.
Following the 2015 Portuguese legislative elections, a comparison between actual seat allocation and simulations of nationwide (i.e. ignoring electoral districts) application of d'Hondt and Sainte-Laguë methods.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Following the 2015 Portuguese legislative elections, a comparison between | |
| * actual seat allocation and simulations of nationwide (i.e. ignoring | |
| * electoral districts) application of d'Hondt and Sainte-Laguë methods. | |
| * | |
| * The last three column reflect parliamentary seat assignments. | |
| * | |
| * - "Atribuídos" are the actual seats that were assigned following the | |
| * elections | |
| * | |
| * - "Sob d'Hondt" are the seats that would have been assigned if the | |
| * electoral system abandoned electoral districts in favor of nationwide | |
| * assignment. | |
| * | |
| * - "Sob Sainte-Laguë" are the seats that would have been assigned by | |
| * abandoning districts and switching to the Sainte-Laguë assignment | |
| * | |
| * | |
| * Partido Votos Atribuídos Sob d'Hondt Sob Sainte-Laguë | |
| * -------------- ------- ---------- ----------- ---------------- | |
| * PPD/PSD.CDS-PP 1979132 99 90 86 | |
| * PS 1740280 85 79 75 | |
| * BE 549153 19 24 24 | |
| * PCP-PEV 444319 17 20 19 | |
| * PPD/PSD 81054 5 3 4 | |
| * PAN 74656 1 3 3 | |
| * PDR 60912 0 2 3 | |
| * PCTP/MRPP 59812 0 2 3 | |
| * L/TDA 38958 0 1 2 | |
| * PNR 27104 0 1 1 | |
| * MPT 22384 0 1 1 | |
| * PTP-MAS 20690 0 0 1 | |
| * NC 18695 0 0 1 | |
| * PPM 14799 0 0 1 | |
| * JPP 14196 0 0 1 | |
| * PURP 13739 0 0 1 | |
| * CDS-PP 7536 0 0 0 | |
| * CDS-PP.PPM 3654 0 0 0 | |
| * PPV/CDC 2658 0 0 0 | |
| * PTP 1748 0 0 0 | |
| * | |
| * | |
| * The source-code that generated the table follows. | |
| */ | |
| import R from 'ramda'; | |
| import Table from 'easy-table'; | |
| // data Party = (Number, Number) | |
| // | |
| // A Party is a pair of: | |
| // - number of votes | |
| // - number of allocated seats | |
| // quotSainteLague :: Party -> Number | |
| const quotSainteLague = ([v, s]) => v / (2 * s + 1); | |
| // quotDHondt :: Party -> Number | |
| const quotDHondt = ([v, s]) => v / (s + 1); | |
| // compareAssignments :: Number -> [Number] -> [(Number, Number, Number)] | |
| const compareAssignments = (maxSeats, votes) => | |
| R.zipWith( | |
| (a, b) => [a[0], a[1], b[1]], | |
| assignSeats(quotSainteLague, maxSeats, votes), | |
| assignSeats(quotDHondt, maxSeats, votes) | |
| ); | |
| // assignSeats :: Function -> Number -> [Number] -> [Party] | |
| const assignSeats = (quot, maxSeats, votes) => | |
| R.repeat(null, maxSeats).reduce(nextRound(quot), votes.map(v => [v, 0])); | |
| // nextRound :: Function -> [Party] -> [Party] | |
| const nextRound = R.curry((quot, ps) => { | |
| const i = nextWinner(quot, ps); | |
| const p = [ ps[i][0], ps[i][1] + 1 ]; | |
| return replaceAtIndex(i, p, ps); | |
| }); | |
| // nextWinner :: Function -> [Party] -> Number | |
| const nextWinner = (quot, ps) => indexOfMax(ps.map(quot)); | |
| // indexOfMax :: [Number] -> Number | |
| const indexOfMax = R.converge(R.indexOf, R.apply(Math.max), R.identity); | |
| // replaceAtIndex :: Number -> a -> [a] -> [a] | |
| const replaceAtIndex = (index, x, xs) => | |
| [ ...xs.slice(0, index), x, ...xs.slice(index + 1) ]; | |
| const compare2015 = () => { | |
| const seats = 226; | |
| const votes = [ | |
| [ 1979132, 'PPD/PSD.CDS-PP', 99 ], | |
| [ 1740280, 'PS', 85 ], | |
| [ 549153, 'BE', 19 ], | |
| [ 444319, 'PCP-PEV', 17 ], | |
| [ 81054, 'PPD/PSD', 5 ], | |
| [ 74656, 'PAN', 1 ], | |
| [ 60912, 'PDR', 0 ], | |
| [ 59812, 'PCTP/MRPP', 0 ], | |
| [ 38958, 'L/TDA', 0 ], | |
| [ 27104, 'PNR', 0 ], | |
| [ 22384, 'MPT', 0 ], | |
| [ 20690, 'PTP-MAS', 0 ], | |
| [ 18695, 'NC', 0 ], | |
| [ 14799, 'PPM', 0 ], | |
| [ 14196, 'JPP', 0 ], | |
| [ 13739, 'PURP', 0 ], | |
| [ 7536, 'CDS-PP', 0 ], | |
| [ 3654, 'CDS-PP.PPM', 0 ], | |
| [ 2658, 'PPV/CDC', 0 ], | |
| [ 1748, 'PTP', 0 ], | |
| ]; | |
| console.log(Table.print( | |
| compareAssignments(seats, votes.map(R.nth(0))) | |
| .map((line, i) => ({ | |
| 'Partido': votes[i][1], | |
| 'Votos': line[0], | |
| 'Atribuídos': votes[i][2], | |
| 'Sob d\'Hondt': line[2], | |
| 'Sob Sainte-Laguë': line[1], | |
| })) | |
| )); | |
| }; | |
| compare2015(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment