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