1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::cmp::Ordering;
pub fn apportion(votes: &[u64], seat_number: u64) -> Vec<u64> {
let total: u64 = votes.iter().sum();
let hare_quota = total as f64 / seat_number as f64;
let votes_quota: Vec<f64> = votes
.iter()
.map(|vote| (*vote as f64) / hare_quota)
.collect();
let mut seats: Vec<u64> = votes_quota.iter().map(|v| v.floor() as u64).collect();
let mut remainders: Vec<(f64, u64)> = votes_quota
.iter()
.enumerate()
.map(|(i, v)| (v.fract(), i as u64))
.collect();
let total_seat: u64 = seats.iter().sum();
let remaining_seat: u64 = seat_number - total_seat;
remainders.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
remainders.reverse();
let highest_remainder_seats: Vec<u64> = remainders
.iter()
.take(remaining_seat as usize)
.map(|v| v.1)
.collect();
for index in highest_remainder_seats {
seats[index as usize] += 1;
}
seats
}
#[cfg(test)]
mod tests {
use super::apportion;
#[test]
fn test_apportion() {
let votes = vec![47_000, 16_000, 15_800, 12_000, 6_100, 3_100];
let seats = 10;
let total_seats = apportion(&votes, seats);
assert_eq!(vec![5, 2, 1, 1, 1, 0], total_seats);
}
#[test]
fn test_apportion_again() {
let votes = vec![1500, 1500, 900, 500, 500, 200];
let seats = 25;
let total_seats = apportion(&votes, seats);
assert_eq!(vec![7, 7, 4, 3, 3, 1], total_seats);
let new_seats = 26;
let new_total_seats = apportion(&votes, new_seats);
assert_eq!(vec![8, 8, 5, 2, 2, 1], new_total_seats);
}
}