IrvRound<TCandidate extends Comparable> constructor
IrvRound<TCandidate extends Comparable> (
- int roundNumber,
- List<
RankedBallot< ballots,TCandidate> > - Iterable<
TCandidate> eliminatedCandidates
Implementation
factory IrvRound(
int roundNumber,
List<RankedBallot<TCandidate>> ballots,
Iterable<TCandidate> eliminatedCandidates,
) {
final cleanedBallots = ballots.map((b) {
final pruned = b.rank
.where((c) => !eliminatedCandidates.contains(c))
.toList(growable: false);
final winner = pruned.isEmpty ? null : pruned[0];
return _CleanedBallot<TCandidate>(b, pruned, winner);
});
final candidateAllocations =
groupBy<_CleanedBallot<TCandidate>, TCandidate>(
cleanedBallots.where((cb) => cb.winner != null),
(cb) => cb.winner!,
);
final voteGroups = groupBy<TCandidate, int>(
candidateAllocations.keys, (c) => candidateAllocations[c]!.length);
final placeVotes = voteGroups.keys.toList(growable: false)
// reverse sorting -> most votes first
..sort((a, b) => b.compareTo(a));
var placeNumber = 1;
final places = placeVotes.map((vote) {
final voteGroup = voteGroups[vote]!..sort();
final currentPlaceNumber = placeNumber;
placeNumber += voteGroup.length;
return PluralityElectionPlace<TCandidate>(
currentPlaceNumber, voteGroup, vote);
}).toList(growable: false);
final newlyEliminatedCandidates =
_getEliminatedCandidates<TCandidate>(places);
final eliminations = newlyEliminatedCandidates.map((TCandidate c) {
final transfers = <TCandidate, List<RankedBallot<TCandidate>>>{};
final exhausted = <RankedBallot<TCandidate>>[];
for (var cb in cleanedBallots.where((cb) => cb.winner == c)) {
final rb = cb.ballot;
final pruned =
cb.remaining.where((c) => !newlyEliminatedCandidates.contains(c));
if (pruned.isEmpty) {
// we're exhausted
exhausted.add(rb);
} else {
// #2 gets the transfer
final runnerUp = pruned.first;
transfers.putIfAbsent(runnerUp, () => []).add(rb);
}
}
return IrvElimination<TCandidate>(c, transfers, exhausted);
}).toList(growable: false);
return IrvRound<TCandidate>._internal(
roundNumber,
places,
eliminations,
);
}