- array_sum: documentation ( source)
- array_reverse: documentation ( source)
- floor: documentation ( source)
- asort: documentation ( source)
- key: documentation ( source)
- next: documentation ( source)
<?php
/**
* Class AreaModel
*/
class HareNiemeier
{
/**
*
*
* @var array
*/
protected $_votes = array();
/**
*
*
* @var array
*/
protected $_slots = array();
/**
*
*
* @var integer
*/
protected $_maxSlots = 0;
/**
*
*
* @param integer $slots
* @return void
*/
public function __construct($slots)
{
$this->_maxSlots = $slots;
}
/**
*
*
* @param string $partyName
* @param integer $votes
* @return void
*/
public function setPartyVotes($partyName, $votes)
{
$this->_votes[$partyName] = $votes;
}
/**
*
*
* @throws Exception
* @return void
*/
public function doElection()
{
$votesSum = array_sum($this->_votes);
if (0 >= $votesSum) {
throw new Exception('Votes count have to be greater than zero!');
}
// First-time distribution by integer part
$fractionals = array();
foreach ($this->_votes as $name => $votes) {
$quote = $votes * $this->_maxSlots / $votesSum;
$this->_slots[$name] = floor($quote);
$fractionals[$name] = $quote - $this->_slots[$name];
}
// Distribution of the rest by fractional part
$restSlots = $this->_maxSlots - array_sum($this->_slots);
asort($fractionals);
$fractionals = array_reverse($fractionals);
while (0 < $restSlots--) {
$this->_slots[key($fractionals)]++;
next($fractionals);
}
}
/**
*
*
* @return void
*/
public function publicateResults()
{
echo "<pre>\n";
foreach ($this->_slots as $name => $slots) {
echo "{$name}: {$slots} places\n";
}
echo '</pre>';
}
}
$election = new HareNiemeier(15);
$election->setPartyVotes('A', 15000);
$election->setPartyVotes('B', 5400);
$election->setPartyVotes('C', 5500);
$election->setPartyVotes('D', 5550);
$election->doElection();
$election->publicateResults();