And the ballots are in (Alaska special election RCV)
-
I found them here. https://www.elections.alaska.gov/election-results/e/?id=22prim
Click on "Cast vote record"
It's a zip file, the main files you want are CvrExport.json (373 megs!) and CandidateManifest.json.
I read it in and took a look around, there are 192,289 records within, that are complete ballots (including for other elections). They are in the Json object in an array called "Sessions", each member of which you'll dig in to find Original.Cards[].Contests[].Marks. Or something like that.
This is election Id 69. Petolta is candidate Id 218, Begich is 215, Palin is 217. So in this image I linked below, you can see one ballot picked at random (yep, all that data for a single ballot, that's why the file is so big!), where they ranked Petolta first and Begich second. The file shown at right is the CandidataManifest.json.
I could continue parsing it out but I figured I'd just post this now in case anyone else wants to jump in and .... ya know, see who the Condorcet winner is.
(note: I posted this on reddit/EndFPTP as well)
-
Holy crap Begich is the Condorcet winner.
This is bad for FairVote....
https://www.karmatics.com/voting/alaskaspecial.txt
https://codepen.io/karmatics/pen/ExKZVjM
Here is my code for converting the bulky object from the 373 megabyte JSON into slightly more compact representation (861 bytes.... 0.00001% of the size!)
Hope you like for loops.... sorry not sorry!:
// console.log (ballotsAsString(JSON.parse(data), 69, { // '215': 'a', // begich // '217' : 'b', // palin // '218' : 'c', // peltolta // '214' : 'd' // write in //}); function ballotsAsString(data, electionId, nameMap) { // array of ballots is called "Sessions" var ballots = data.Sessions; var counts = {}; // count of each ballot "signature" for(var i=0; i<ballots.length; i++) { var ballot = ballots[i]; // descend through "Original", and "Cards" var original = ballot.Original; if(original) { var cards = original.Cards; if(cards) { for(var j=0; j<cards.length; j++) { var card = cards[j]; if(card) { for(var k=0; k<card.Contests.length; k++) { var contest = card.Contests[k]; if(contest.Id == electionId) { var stringArray = [], hash = {}, isOvervote = false; var marks = contest.Marks; for(var m=0; m<marks.length; m++) { var mark = marks[m]; var candidateIdStr = nameMap[mark.CandidateId]; // if it exists in hash, this is an overvote if(hash[candidateIdStr]) { isOvervote = true; break; } else { hash[candidateIdStr] = true; stringArray.push(candidateIdStr); //stringArray.push(candidateIdStr + '[' + (10-m) + ']'); } } if(!isOvervote) { // reject ballot if overvote //var s = stringArray.join(' '); var s = stringArray.join('>'); if(counts[s]) { counts[s]++; // already have ballots like it } else { counts[s] = 1; // first one like it } } } } } } } } } // convert to array so we can sort it by count var sortArray = []; for(var x in counts) { sortArray.push({r: x, n: counts[x]}); } sortArray.sort((a, b)=>{return b.n-a.n}); // build final array of strings var outStringArray = []; for(var y=0; y<sortArray.length; y++) { var item = sortArray[y]; outStringArray.push(item.n + ': ' + item.r); } // combine into single string return outStringArray.join('\n'); }
which distills it down to....
a: Begich b: Palin c: Peltolta d: Write-in ------------ 21657: c>a 20522: b>a 19494: c 19134: b 17607: a>b 16174: c>a>b 9960: b>a>c 9957: a 7446: a>c>b 6576: a>b>c 5557: a>c 3162: c>d 2773: 2695: b>c>a 2567: c>b>a 2402: c>d>a>b 2146: c>d>a 1987: c>a>d 1914: c>a>d>b 1193: b>a>d 1143: a>b>d 1002: c>b 836: b>a>d>c 743: a>c>d>b 559: b>c 522: a>c>d 512: a>b>d>c 502: d 497: c>d>b>a 477: b>d 418: a>d 389: d>c>a>b 343: a>d>c>b 315: b>d>a 306: c>a>b>d 298: b>d>a>c 287: a>d>b 278: b>a>c>d 257: c>d>b 256: d>a>c>b 240: d>c>a 222: d>c 220: d>a>b 219: d>a 204: a>d>b>c 184: a>b>c>d 179: d>a>b>c 156: a>d>c 147: d>a>c 138: a>c>b>d 131: d>b>a>c 125: b>d>c>a 116: d>b>a 103: d>b 98: d>c>b>a 88: b>c>a>d 82: c>b>a>d 78: c>b>d 70: c>b>d>a 67: b>c>d>a 47: d>b>c>a 33: b>c>d 31: b>d>c 23: d>b>c 20: d>c>b