Ce n'est pas qui vote qui compte; c'est qui compte les votes [fermé]

33

Le scénario

Vous vivez dans un pays qui a une élection présidentielle. Chaque électeur obtient une voix et il existe donc un système bipartite bien enraciné. (Les tiers existent, mais obtiennent peu de voix).

Le dernier sondage d'opinion montre que la course est au point mort:

  • 49%: Alberto Arbusto
  • 49%: Jorge Sangre
  • 2%: divers candidats mineurs

Les exigences du programme

Le gouvernement vous a embauché pour écrire une partie du logiciel de décompte des voix. Vous obtiendrez, en entrée standard, une liste non ordonnée des votes d’un bureau de vote, un par ligne, comme ceci:

Alberto Arbusto
Jorge Sangre
Jorge Sangre
Alberto Arbusto
Jorge Sangre
Alberto Arbusto
Alberto Arbusto
Jorge Sangre
Juan Perez
Jorge Sangre
Alberto Arbusto
Alberto Arbusto
…

et, après avoir lu tous les votes, génère un résumé du nombre de votes obtenus par chaque candidat, triés par ordre décroissant selon le nombre de votes, comme suit:

492 Jorge Sangre
484 Alberto Arbusto
 18 Juan Perez
  6 Mickey Mouse

La partie sournoise

Vous êtes un partisan qui veut voler l'élection de l'un des deux principaux candidats (vous pouvez choisir lequel). Ainsi, votre programme doit délibérément imprimer des comptes de vote incorrects , avec un parti pris systématique pour votre candidat préféré.

Bien sûr, vous devez faire cela de manière à ce qu'une personne consultant votre code ou sa sortie ne reconnaisse probablement pas le comportement incorrect.

dan04
la source
2
Que diriez-vous de laisser la personne qui dirige le programme choisir à qui elle veut faire la part belle? Cela 1 : rend le défi moins large (une bonne chose), 2 : rend les réponses plus intéressantes (IMO)
Justin
1
...you can choose which one...Puis-je choisir celui dont le nom est le premier?
user80551
2
Par "biaisé", vous voulez dire que le candidat que vous préférez doit être élu, ou que le programme produira simplement un nombre de voix supérieur à celui qui est contenu dans le fichier d’entrée?
3
Il pourrait être difficile de justifier un long programme dans Bash, étant donné qu'un programme non sournois pour compter les votes dans ce format serait littéralement sort|uniq -c...
1
@Alessandro: Il doit simplement générer un nombre de voix plus élevé pour lui (et / ou un nombre de voix plus faible pour son adversaire) par rapport à ce qui est réellement entré. L'élection est supposée être suffisamment proche pour qu'une petite erreur puisse la renverser.
dan04

Réponses:

32

Scala

Longue vie à Alberto Arbusto!

import scala.io.Source
import java.util.concurrent.atomic.LongAdder

object Votes extends App {
  val votes = Source.stdin.getLines.toIndexedSeq
  val registeredCandidates = Seq(
    "Alberto Arbusto",
    "Juan Perez",
    "Mickey Mouse",
    "Jorge Sangre"
  )

  val summaries = registeredCandidates map (Summary.apply(_, new LongAdder))

  var currentCandidate: String = _

  for (vote <- votes.par) {
    currentCandidate = vote
    summaries.find(s => s.candidate == currentCandidate).map(_.total.increment)
  }

  for (summary <- summaries.sortBy(-_.total.longValue)) {
    println(summary)
  }
}

case class Summary(candidate: String, total: LongAdder) {
  override def toString = s"${total.longValue} ${candidate}"
}

Alberto Arbusto devancera presque toujours légèrement Jorge Sangre, à condition que suffisamment de suffrages soient exprimés (~ 10 000). Il n'est pas nécessaire de toucher aux votes eux-mêmes.

Il y a une condition de concurrence. Et en mettant Alberto Arbusto plus tôt dans la liste, nous augmentons ses chances de remporter la course.

Note latérale: Ce code est vaguement basé sur un pool de connexions "personnalisé" que j'ai rencontré sur un projet. Il nous a fallu des semaines pour comprendre pourquoi l'application était constamment en rupture de connexion.

James_pic
la source
12
J'aime celui-ci à cause du déni plausible que cela donne.
dan04
16

Rubis

vote_counts = $<.readlines.group_by{|s|s}.collect{ |name, votes| [votes.count, name] }

formatted_count_strings = vote_counts.map do |row,
  formatter = PrettyString.new|"%#{formatter[1][/[so]/]||'s'} %s"%
  [row,formatter]
end

sorted_count_strings = formatted_count_strings.sort_by(&:to_i).reverse

puts sorted_count_strings

Jorge Sangre bénéficiera d'une augmentation substantielle de son nombre de votes (par exemple, 492 votes seront rapportés comme 754). Les votes d'Alberto seront rapportés avec précision.

Comme vous pouvez le deviner, ce n’est pas celui qui compte les votes mais celui qui les formate. J'ai essayé de l'obscurcir (ce PrettyString.newn'est pas une chose réelle et on ne l'appelle jamais), mais formatterc'est en fait la chaîne de nom. Si la deuxième lettre du nom est «o», le décompte des votes sera imprimé en octal au lieu de décimal.

histocrate
la source
9

Frapper

(Est-ce que cela répond aux spécifications?)

uniq -c|sort -rk2,2|uniq -f1|sort -gr

Comme toujours, cela nécessite des précautions supplémentaires pour assurer une sortie valide.

uniq -cpréfixe chaque ligne avec le nombre de fois où elle se produit. Cela fait essentiellement tout le travail.

Juste au cas où uniq -cquelque chose ne va pas, nous trions maintenant sa sortie en fonction du nom des candidats dans l’ordre inverse, puis nous l'exécutons uniq -f1(n'imprimez pas les lignes en double, en ignorant le premier champ [le nombre de voix]) pour supprimer les candidats en double. Enfin, nous utilisons sort -grle tri dans l'ordre "Numérique général" et "Inversé" (ordre décroissant selon le nombre de votes).

uniq -ccompte les occurrences consécutives et non les occurrences sur tout le fichier. Le gagnant sera le candidat avec le plus de votes consécutifs.


la source
16
Comment cela favorise-t-il un candidat en particulier? Vous avez simplement changé la condition de victoire de l'élection. (Ce serait le chaos si les élections étaient réellement décidées :). Vous obtiendrez des groupes Internet géants s'organisant pour voter de manière séquentielle)
Cruncher le
1
@Cruncher dans les commentaires sur la question, le demandeur dit qu'il est correct de choisir le prénom dans le fichier, ce qui est probablement très bien aussi
9

C #

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        var candidates = new SortedDictionary<string, int>();
        string candidate;
        using (var sr = new StreamReader("candidates.txt"))
        {
            while ((candidate = sr.ReadLine()) != null)
            {
                if (candidates.ContainsKey(candidate)) 
                    candidates[candidate]++;
                else 
                    candidates.Add(candidate, 1);
            }
        }

        // order by the votes
        var votes = candidates.OrderByDescending(k => k.Value).Select(x => x.Value);

        Console.WriteLine("Candidate | Votes"); 
        for (int i = 0; i < candidates.Count; i++)
        {   
            Console.WriteLine(candidates.ElementAt(i).Key + " " + votes.ElementAt(i));
        }

        Console.ReadKey();
    }
}

Le premier candidat dans le fichier texte gagnera toujours!

Cela fera d' Alberto Arbusto le gagnant!

Les noms des candidats sont classés par ordre alphabétique dans le dictionnaire, mais les votes sont classés par numéro.

mai
la source
Alors, est-ce que cela va simplement remettre l'élection au premier candidat par ordre alphabétique, ou peut-il être manipulé pour préférer n'importe quel candidat que nous aimons?
James_pic
Il ne trie pas les candidats par ordre alphabétique. Il ne fait que trier les votes. Vous pouvez manipuler n'importe quel candidat pour gagner. Assurez-vous simplement qu'il est le premier dans le fichier texte.
mai
Mais IIUC SortedDictionary va trier les candidats par ordre alphabétique.
James_pic
Oh je vois. Il pourrait y avoir une erreur ici. Laissez-moi le tester à nouveau.
mai
1
@James_pic: La table de hachage de la Dictionary<TK,TV>classe, telle qu'implémentée , stocke les index dans un tableau de sauvegarde d'éléments réels. Un Dictionary<TK,TV> élément dans lequel aucun élément n'est jamais supprimé énumérera les éléments dans l'ordre dans lequel ils ont été ajoutés; un tel comportement n'est pas spécifié, mais il est en place depuis assez longtemps et je ne m'attendrais pas à ce que MS le change jamais.
Supercat
7

C

#include <stdio.h>

#define NCANDIDATES 4
static const char * const cand_list[NCANDIDATES] = {
    "Alberto Arbusto",
    "Juan Perez",
    "Mickey Mouse",
    "Jorge Sangre"
};

#define BUFFER_SIZE 100

int
main(int argc, char **argv)
{
    int votes[NCANDIDATES];
    int candidate;
    size_t name_start;
    int i;
    int j;
    int place;
    int max;
    size_t bytes;
    char buffer[BUFFER_SIZE];

    /*
    Make sure input is read in text mode, so we don't have to
    worry about whether line endings are LF or CRLF.
    */
    freopen(NULL, "rt", stdin);

    /* Initialize vote tally. */
    for (candidate = 0; candidate < NCANDIDATES; candidate++) {
        votes[candidate] = 0;
    }

    /* Read and process vote file. */
    do {
        /* Read a block of data. */
        bytes = fread(buffer, 1, BUFFER_SIZE, stdin);

        /* Loop over the data, finding and counting the votes. */
        name_start = 0;
        for (i = 0; i < bytes; i++) {
            if (buffer[i] == '\n') {
                /* Found name. */
                buffer[i] = '\0'; // nul-terminate name so strcmp will work
                /* Look up candidate. */
                for (j = 0; j < NCANDIDATES; j++) {
                    if (strcmp(&buffer[name_start], cand_list[j]) == 0) {
                        candidate = j;
                        break;
                    }
                }
                /* Count vote. */
                ++votes[candidate];

                /* Next name starts at next character */
                name_start = i + 1;
            }
        }
    } while (bytes > 0);

    /* Output the candidates, in decreasing order of votes. */
    for (place = 0; place < NCANDIDATES; place++) {
        max = -1;
        for (j = 0; j < NCANDIDATES; j++) {
            if (votes[j] > max) {
                candidate = j;
                max = votes[j];
            }
        }
        printf("%8d %s\n", votes[candidate], cand_list[candidate]);
        votes[candidate] = -1; // Remove from consideration for next place.
    }

    return 0;
}

Favorise Jorge Sangre.

Lors des tests avec des fichiers de votes générés aléatoirement, même lorsque Alberto Arbusto reçoit jusqu'à 1,4% de votes supplémentaires (49,7% contre 48,3% pour Jorge Sangre), mon homme, Jorge Sangre, remporte généralement le décompte.

La lecture des données dans des blocs de taille fixe divise souvent une ligne en deux blocs. Le fragment de la ligne à la fin du premier bloc n'est pas compté car il n'a pas de caractère de nouvelle ligne. Le fragment du deuxième bloc génère un vote, mais il ne correspond à aucun nom du candidat. La variable "candidat" n'est donc pas mise à jour. Cela a pour effet de transférer un vote du candidat dont le nom a été scindé au candidat ayant obtenu le vote précédent. Un nom plus long étant plus susceptible d’être divisé en blocs, Alberto Arbusto finit par être un "donneur" de vote plus souvent que Jorge Sangre.

Gary Culp
la source
5

Python

from collections import defaultdict

def count_votes(candidate, votes=defaultdict(int)):
    with open('votes.txt') as f:
        for line in f:
            votes[line.strip()] += 1

    return votes[candidate]

if __name__ == '__main__':
    candidates = [
        'Mickey Mouse',
        'Juan Perez',
        'Alberto Arbusto',
        'Jorge Sangre'
    ]

    results = {candidate: count_votes(candidate) for candidate in candidates}

    for candidate in sorted(results, key=results.get, reverse=True):
        print results[candidate], candidate

Le décompte des voix favorisera les candidats plus proches de la fin de la liste.

En Python, les arguments mutables par défaut sont créés et liés à la fonction lors de la définition. Les votes seront donc maintenus entre les appels de fonctions et reportés aux candidats suivants. Le nombre de votes sera compté deux fois pour le deuxième candidat, trois fois pour le troisième et ainsi de suite.

grc
la source
2
À l'exception du fait que le nombre total de votes n'est plus compatible avec les données d'entrée, celui-ci m'avait.
Zaid
0

tr | sed | dc

tr ' [:upper:]' '\n[:lower:]' <votes |\
sed -e '1i0sa0ss0sp' -e \
    '/^[asp]/!d;s/\(.\).*/l\1 1+s\1/
    ${p;c[Alberto Arbusto: ]P lap[Jorge Sangre: ]P lsp[Juan Perez: ]P lpp
    }' | dc

Cela compte mon copain Alberto deux fois à chaque fois.

"Oh - tr? Bien, c'est juste nécessaire parce que les ordinateurs ne sont pas très bons en majuscules - mieux s'ils sont tous en minuscules ... Ouais, je sais, les ordinateurs sont fous."

SORTIE

Alberto Arbusto: 12
Jorge Sangre: 5
Juan Perez: 1

Voici une autre version qui donne le vote de Juan Perez à Jorge Sangre:

tr '[:upper:]' '[:lower:]' <votes |\
sed -e '1i0sj0sa1so' -e \
    's/\(.\).*/l\1 1+s\1/
    ${p;c[Alberto Arbusto: ]P lap[Jorge Sangre: ]P ljp[Others: ]P lop
    }' | dc

SORTIE

Alberto Arbusto: 6
Jorge Sangre: 6
Others: 1
Mikeserv
la source
0

JavaScript

    function Election(noOfVoters) {
    candidates = ["Albert", "Jorge", "Tony", "Chip"];
    votes = [];

    for (i = 1; i <= noOfVoters; i++) {

        votes.push(prompt("1 - Albert, 2 - Jorge, 3 - Tony , 4 - Chip"))

    }
    votes.sort();
    WinningOrder = count(votes);

    var placement = [];

    for (x = 0; x < candidates.length; x++) {
        placement.push(x + " place with " + WinningOrder[x] + " votes is " + candidates[x] + "\n");
    }
    placement.reverse();
    alert(placement)
}


function count(arr) {
    var a = [],
        b = [],
        prev;

    arr.sort();
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] !== prev) {
            a.push(arr[i]);
            b.push(1);
        } else {
            b[b.length - 1]++;
        }
        prev = arr[i];
    }

    b.sort();

    return b;
}

La dernière personne dans la liste des candidats sera toujours gagnante.

Xevvii
la source