private MeetingElectionCandidates GenerateBallot(MeetingElectionCandidates rawList, int candidateCount, BallotCompositionMethod method) { MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary <int, bool> takenCandidates = new Dictionary <int, bool>(); if (candidateCount == -1) { candidateCount = rawList.Count; } // First, cancel out the defected candidates. Expensive op, but don't care. for (int rawIndex = 0; rawIndex < rawList.Count; rawIndex++) { if (CandidatePersonIdDefected(rawList[rawIndex].PersonId)) { takenCandidates[rawIndex] = true; } } if (candidateCount == rawList.Count) { candidateCount -= takenCandidates.Count; } // Assemble list. while (result.Count < candidateCount) { // Add a candidate. // // Should we add a candidate from the raw list or from the quoted master list? int masterPosition = GetMasterListPosition(result.Count + 1, method); if (masterPosition > 0) { // We should add a candidate from the master list, no quota calculations, BUT ONLY if this candidate // hasn't already been added from the district list. int rawListIndex = FindCandidateIndex(QuotedMasterList[masterPosition - 1].InternalPollCandidateId, rawList); if (rawListIndex >= 0 && !takenCandidates.ContainsKey(rawListIndex)) { // The master list candidate is also on the district list, but has not been added. Add // the candidate in the master list position. result.Add(QuotedMasterList[masterPosition - 1]); takenCandidates[rawListIndex] = true; continue; } if (rawListIndex == -1) { // The master list candidate is not on the district list. Add the candidate. result.Add(QuotedMasterList[masterPosition - 1]); continue; } // Getting here, the candidate on the master position had already been placed on the list through his // or her district, so fallthrough to local candidates for this master position } // Add a candidate from the local list. First, try adding the next available candidate. // If this puts us outside of the allowed gender quota, pick the next candidate of the // underrepresented gender instead. int nextCandidateIndex = 0; while (takenCandidates.ContainsKey(nextCandidateIndex)) { nextCandidateIndex++; } PersonGender candidateGender = rawList[nextCandidateIndex].Person.Gender; double currentMaleQuota = CalculateListMaleQuota(result, candidateGender); // Here, we account an extremely rare situation where the correct quota is not even obtainable, e.g. // for position #3 where #1 is male and #2 is female and with a quota of 40%. Either way, it will // fall outside of bounds (33% or 66%). If so, ignore the quota if it is not obtainable. PersonGender oppositeGender = (candidateGender == PersonGender.Male ? PersonGender.Female : PersonGender.Male); double alternateMaleQuota = CalculateListMaleQuota(result, oppositeGender); // If currentMaleQuota is outside of bounds AND the alternate quota IS inside of bounds... if (currentMaleQuota < GenderQuota || currentMaleQuota > (1.0 - GenderQuota)) { if (alternateMaleQuota >= GenderQuota && alternateMaleQuota <= (1.0 - GenderQuota)) { // ...pick the alternate (underrepresented) candidate try { nextCandidateIndex = GetNextSpecificGenderCandidate(rawList, takenCandidates, oppositeGender); } catch (ArgumentOutOfRangeException) { // there isn't any more candidate of the requested gender, so go with what we have } } } result.Add(rawList[nextCandidateIndex]); takenCandidates[nextCandidateIndex] = true; } return(result); }
private MeetingElectionCandidates GenerateBallot (MeetingElectionCandidates rawList, int candidateCount, BallotCompositionMethod method) { MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary<int, bool> takenCandidates = new Dictionary<int, bool>(); if (candidateCount == -1) { candidateCount = rawList.Count; } // First, cancel out the defected candidates. Expensive op, but don't care. for (int rawIndex = 0; rawIndex < rawList.Count; rawIndex++) { if (this.CandidatePersonIdDefected(rawList [rawIndex].PersonId)) { takenCandidates[rawIndex] = true; } } if (candidateCount == rawList.Count) { candidateCount -= takenCandidates.Count; } // Assemble list. while (result.Count < candidateCount) { // Add a candidate. // // Should we add a candidate from the raw list or from the quoted master list? int masterPosition = GetMasterListPosition (result.Count + 1, method); if (masterPosition > 0) { // We should add a candidate from the master list, no quota calculations, BUT ONLY if this candidate // hasn't already been added from the district list. int rawListIndex = FindCandidateIndex (QuotedMasterList[masterPosition - 1].InternalPollCandidateId, rawList); if (rawListIndex >= 0 && !takenCandidates.ContainsKey(rawListIndex)) { // The master list candidate is also on the district list, but has not been added. Add // the candidate in the master list position. result.Add(QuotedMasterList[masterPosition - 1]); takenCandidates[rawListIndex] = true; continue; } if (rawListIndex == -1) { // The master list candidate is not on the district list. Add the candidate. result.Add(QuotedMasterList[masterPosition - 1]); continue; } // Getting here, the candidate on the master position had already been placed on the list through his // or her district, so fallthrough to local candidates for this master position } // Add a candidate from the local list. First, try adding the next available candidate. // If this puts us outside of the allowed gender quota, pick the next candidate of the // underrepresented gender instead. int nextCandidateIndex = 0; while (takenCandidates.ContainsKey(nextCandidateIndex)) { nextCandidateIndex++; } PersonGender candidateGender = rawList[nextCandidateIndex].Person.Gender; double currentMaleQuota = CalculateListMaleQuota(result, candidateGender); // Here, we account an extremely rare situation where the correct quota is not even obtainable, e.g. // for position #3 where #1 is male and #2 is female and with a quota of 40%. Either way, it will // fall outside of bounds (33% or 66%). If so, ignore the quota if it is not obtainable. PersonGender oppositeGender = (candidateGender == PersonGender.Male ? PersonGender.Female : PersonGender.Male); double alternateMaleQuota = CalculateListMaleQuota(result, oppositeGender); // If currentMaleQuota is outside of bounds AND the alternate quota IS inside of bounds... if (currentMaleQuota < GenderQuota || currentMaleQuota > (1.0 - GenderQuota)) { if (alternateMaleQuota >= GenderQuota && alternateMaleQuota <= (1.0 - GenderQuota)) { // ...pick the alternate (underrepresented) candidate try { nextCandidateIndex = GetNextSpecificGenderCandidate(rawList, takenCandidates, oppositeGender); } catch (ArgumentOutOfRangeException) { // there isn't any more candidate of the requested gender, so go with what we have } } } result.Add(rawList[nextCandidateIndex]); takenCandidates[nextCandidateIndex] = true; } return result; }
private void AssembleFinalOrder() { Console.WriteLine("Assembling final list."); MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary <int, bool> candidateAdded = new Dictionary <int, bool>(); int candidatesRemaining = this.candidateIds.Count; int count = 1; while (candidatesRemaining > 0) { Console.Write("\r - remaining: {0:D4}", candidatesRemaining); // Find the first nontaken candidate int winningCandidateIndex = 0; while (candidateAdded.ContainsKey(winningCandidateIndex)) { winningCandidateIndex++; } // Iterate over all linkStrength[X,*] and [*,X]; this candidate is only a winner if // all [X,*] are >= all [*,X]. bool allSuperior = false; while (!allSuperior) { allSuperior = true; for (int compareCandidateIndex = 0; compareCandidateIndex < this.candidateIds.Count; compareCandidateIndex++) { if (candidateAdded.ContainsKey(compareCandidateIndex)) { continue; } if (this.linkStrengthXtoY[winningCandidateIndex, compareCandidateIndex] < this.linkStrengthXtoY[compareCandidateIndex, winningCandidateIndex]) { // the compareCandidateIndex had a greater link strength, so jump there and take it as // a new potential winner, restarting the comparison winningCandidateIndex = compareCandidateIndex; allSuperior = false; break; } } } // We have the winning candidate among the not-yet-ranked candidates: MeetingElectionCandidate candidate = MeetingElectionCandidate.FromIdentity(this.candidateIds[winningCandidateIndex]); candidateAdded[winningCandidateIndex] = true; result.Add(candidate); candidatesRemaining--; count++; } FinalOrder = result; Console.WriteLine(", done."); }
private void AssembleFinalOrder() { Console.WriteLine("Assembling final list."); MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary<int, bool> candidateAdded = new Dictionary<int, bool>(); int candidatesRemaining = candidateIds.Count; int count = 1; while (candidatesRemaining > 0) { Console.Write("\r - remaining: {0:D4}", candidatesRemaining); // Find the first nontaken candidate int winningCandidateIndex = 0; while (candidateAdded.ContainsKey(winningCandidateIndex)) { winningCandidateIndex++; } // Iterate over all linkStrength[X,*] and [*,X]; this candidate is only a winner if // all [X,*] are >= all [*,X]. bool allSuperior = false; while (!allSuperior) { allSuperior = true; for (int compareCandidateIndex = 0; compareCandidateIndex < candidateIds.Count; compareCandidateIndex++) { if (candidateAdded.ContainsKey(compareCandidateIndex)) { continue; } if (linkStrengthXtoY[winningCandidateIndex, compareCandidateIndex] < linkStrengthXtoY[compareCandidateIndex,winningCandidateIndex]) { // the compareCandidateIndex had a greater link strength, so jump there and take it as // a new potential winner, restarting the comparison winningCandidateIndex = compareCandidateIndex; allSuperior = false; break; } } } // We have the winning candidate among the not-yet-ranked candidates: MeetingElectionCandidate candidate = MeetingElectionCandidate.FromIdentity(candidateIds[winningCandidateIndex]); candidateAdded[winningCandidateIndex] = true; result.Add(candidate); candidatesRemaining--; count++; } FinalOrder = result; Console.WriteLine(", done."); }