Statistiche polling ingegnere inverso


22

introduzione

Data una serie di percentuali di scelte in un sondaggio, calcola il numero minimo di elettori che devono esserci nel sondaggio per generare tali statistiche.

Esempio: qual è il tuo animale preferito?

  • Cane: 44.4%
  • Gatto: 44.4%
  • Topo: 11.1%

Produzione: 9 (numero minimo possibile di elettori)

Specifiche

Ecco i requisiti per il tuo programma / funzione:

  • Viene fornito un array di valori percentuali come input (su stdin, come argomento di funzione, ecc.)
  • Ogni valore percentuale è un numero arrotondato al primo decimale (ad esempio, 44.4 44.4 11.1).
  • Calcola il numero minimo possibile di elettori nel sondaggio i cui risultati darebbero quelle percentuali esatte se arrotondato al primo decimale (su stdout o valore di ritorno della funzione).
  • Bonus : -15 caratteri se riesci a risolverli in modo "non banale" (ovvero, non comporta l'iterazione attraverso ogni possibile numero di elettori fino a quando non trovi il primo che funziona)

Esempio

>./pollreverse 44.4 44.4 11.1
9
>./pollreverse 26.7 53.3 20.0
15
>./pollreverse 48.4 13.7 21.6 6.5 9.8
153
>./pollreverse 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 99.6
2000
>./pollreverse 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 98.7
667
>./pollreverse 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 98.7
2000
>./pollreverse 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 97.8
401

punteggio

Si tratta di code-golf, quindi i personaggi più corti possibili vincono. Eventuali bonus vengono ulteriormente sottratti dal conteggio totale dei personaggi.


2
Penso che questo potrebbe fare con alcuni casi più imbarazzanti per i test. 26.7 53.3 20.0(4 8 3 di 15), 48.4 13.7 21.6 6.5 9.8(74 21 33 10 15 di 153) ecc.
Gareth

@Gareth: buona idea. Aggiornato con i casi di test.
mellamokb,

la somma di tutti i voti non dovrebbe essere del 100%? non è nelle ultime quattro prove
Ali1S232,

@Gajet: No, non è sempre uguale al 100%. Ogni volta che c'è un arrotondamento per difetto, perdi fino al 0.5%totale, e ogni volta che c'è un arrotondamento per eccesso, sommi 0.5%al totale. Gli ultimi quattro casi di test sono stati appositamente costruiti per sfruttare in modo ottimale questo fenomeno. Nel primo caso di test che ne risulta 2000, ciascuna delle prime 9 voci rappresenta il 1voto (e sono tutte arrotondate per eccesso 0.5%), mentre l'ultima rappresenta i 1991voti (ed è arrotondata per difetto ~ 0.5%). Se calcoli queste percentuali manualmente e arrotondiamo al primo decimale, vedrai che sono tutte corrette.
mellamokb

Sto lottando con la risposta non banale in VBA (provando da ora, non ce ne sono stati), ma ci sto lavorando!
Gaffi,

Risposte:


2

APL (Dyalog Classic) , 48 43 byte

-5 byte di Adám

+/0(⊢+{(⌈/⍷⊢)⍺-⍵÷+/⍵})⍣{z≡⍎3⍕⍺÷+/⍺}⍨z←.01×⎕

Programma completo che accetta input da stdin.

Provalo online!Il collegamento è alla versione di dfn.

Ungolfed

normalize   ÷ +/
find_max  {⍵⍷⍨⌈/⍵}
round  {⍎3⍕⍵}
increase  {find_max  - normalize ⍵}
vote_totals  {z←⍺   (⊢+increase)⍣{z  round normalize ⍺} ⍵}
h  {+/ (.01×⍵) vote_totals 0}

Provalo online!

  • normalizedivide ( ÷) tutti gli elementi del suo giusto argomento ( ) per la sua somma (+/ ).
  • round(y)arrotonda y al terzo decimale formattando ( ) e quindi valutando ( ) ogni elemento di y.
  • find_max(y) restituisce un array con 1 dove si trova max (y) e 0 altrove.
  • increase(x,y) prende x (le percentuali di obiettivo) e y (la matrice dei totali dei voti correnti) e calcola dove aggiungere 1 in y per avvicinare le percentuali a x.
  • vote_totals(x,y) prende x (le percentuali obiettivo) e y (il totale dei voti iniziali) ed esegue f ripetutamente, aggiungendo voti fino a quando le percentuali si arrotondano a x.
    • La sintassi f ⍣ gsignifica eseguire fripetutamente fino a quando non g(y,f(y))è vero. In questo caso ignoriamo f(y).
  • h(x) imposta y su 0 (equivalente a un array di 0 dovuto alla vettorializzazione), esegue g e somma i totali del voto finale.

7

Python, 154

def p(x):
 n=[1]*len(x);d=2;r=lambda z:round(1000.*z/d)/10
 while 1:
    if(map(r,n),sum(n))==(x,d):return d
    d+=1
    for i in range(len(x)):n[i]+=r(n[i])<x[i]

Funziona per l'ultimo esempio ora.

Esempi di esecuzione:

>>> p([44.4, 44.4, 11.1])
9
>>> p([26.7, 53.3, 20.0])
15
>>> p([48.4, 13.7, 21.6, 6.5, 9.8])
153
>>> p([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 99.6])
2000
>>> p([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 98.7])
667
>>> p([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 98.7])
2000
>>> p([0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 97.8])
401

Penso che qualcosa possa essere sbagliato nel tuo ultimo esempio; forse intendevi 99.1come ultimo valore
Cristian Lupascu il

2
Penso che sia giusto ma è abbastanza confuso. 1/2000 = 0.05%( 0.1%arrotondato) e 1991/2000 = 99.55%( 99.6%arrotondato). Quindi, se ci sono dieci opzioni in un sondaggio e nove di loro vengono votati per una volta mentre l'ultimo ottiene il 1991 voti, allora darebbe quelle percentuali.
grc

Hai ragione. Ottima soluzione, a proposito.
Cristian Lupascu,

Penso che puoi risparmiare altri 3 caratteri seguendo questo suggerimento: codegolf.stackexchange.com/a/58/3527
Cristian Lupascu

Grazie, w0lf. L'ho aggiornato ora per includere le schede. Le schede vengono visualizzate come quattro spazi se qualcuno si sta chiedendo.
grc,

4

J, 57 caratteri

t=:".>'1'8!:0|:100*%/~i.1001
{.I.*/"1(t{~i.#t)e."1~1!:1[1

Usato il metodo banale. Prende input dalla tastiera.tcrea una tabella di ricerca e la seconda riga cerca l'input all'interno della tabella. Posso fornire una spiegazione estesa del codice se qualcuno è interessato.

Avevo esaminato l'uso della percentuale per creare una frazione, quindi ottenere la forma più bassa della frazione per capire il numero, ma non riuscivo a trovare un modo per farlo funzionare con l'arrotondamento dei risultati.


Hmm, questo fallisce per il nuovo test case. Dovrò cercare una soluzione.
Gareth,

4

Python, 154

def r(l):
 v=0
 while 1:
  v+=1;o=[round(y*v/100)for y in l];s=sum(o)
  if s: 
    if all(a==b for a,b in zip(l,[round(y*1000/s)/10for y in o])):return s

+1 sembra buono! ideone.com/k2Mgb . Ho cercato di trovare un caso patologico per risolverlo e non ci sono riuscito.
mellamokb,

Non riesco a generare su ideone a causa del superamento del limite di tempo, ma quale risultato ottieni [0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,99.6]?
mellamokb,

hmm ... mezz'ora e il programma è ancora in esecuzione. Penso che probabilmente sia sicuro di dire che è un interruttore. tuttavia, non vedo come possa essere una risposta valida perché ammonta al 100,5% e non al 100%
Blazer

2
1/2000 = 0.05% (0.1% arrotondato) e 1991/2000 = 99.55%( 99.6%arrotondato). Quindi in realtà totalizza il 100%, ma l'arrotondamento lo rende davvero confuso.
grc

3

VBA - 541

Ciò ha avuto alcuni evidenti errori, ma è stato il mio tentativo di trovare una soluzione non banale / in loop fino a quando non avrò il numero giusto. Non l'ho completamente giocato a golf, anche se non credo che ci sia molto da aggiungere al riguardo. Tuttavia, ho trascorso troppo tempo su questo, e ora mi fa male la testa. Per non parlare, le regole sono probabilmente molto infrante e si applicano più o meno solo a questi esempi.

Questo fa molto bene per molti semplici test che ho eseguito (cioè anche totali, 2 o 3 input) ma fallisce per alcuni dei test presentati dalla sfida. Tuttavia, ho scoperto che se si aumenta la precisione decimale dell'input (al di fuori dell'ambito della sfida), l'accuratezza migliora.

Gran parte del lavoro prevede la ricerca del gcd per l'insieme dei numeri forniti, e in qualche modo l'ho superato Function g(), sebbene sia sicuramente incompleto e probabilmente una fonte di almeno alcuni degli errori nei miei output.

L'input è una stringa di valori delimitata da spazi.

Const q=10^10
Sub a(s)
e=Split(s)
m=1
f=UBound(e)
For i=0 To f
t=1/(e(i)/100)
m=m*t
n=IIf(n>t Or i=0,t,n)
x=IIf(x<t Or i=0,t,x)
Next
h=g(n,x)
i=(n*x)/(h)
If Int(i)=Round(Int(i*q)/q) Then
r=i
ElseIf (n+x)=(n*x) Then
r=(1/(n*x))/h/m
ElseIf x=Int(x) Then
r=x*(f+1)
Else
z=((n+x)+(n*x)+m)*h
y=m/(((m*h)/(f+1))+n)
r=IIf(y>z,z,y)
End If
Debug.Print Round(r)
End Sub
Function g(a,b)
x=Round(Int(a*q)/q,3)
y=Round(Int(b*q)/q,3)
If a Then
If b Then
If x>y Then
g=g(a-b,b)
ElseIf y>x Then
g=g(a,b-a)
Else
g=a
End If
End If
Else
g=b
End If
End Function

Testcase (input ==> atteso / restituito):

Passed:  

"95 5" ==> 20/20
"90 10" ==> 10/10
"46.7 53.3" ==> 15/15
"4.7 30.9 40.4 23.8" ==> 42/42
"44.4 44.4 11.1" ==> 9/9
"26.7 53.3 20.0" ==> 15/15
"48.4 13.7 21.6 6.5 9.8" ==> 153/153
"0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 99.55" ==> 2000/2000
"0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 0.15 98.65" ==> 2000/2000
"0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 0.149925 98.65067" ==> 667/667


Failed:  

"0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 99.6" ==> 2000/1000
"0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 98.7" ==> 2000/5000
"0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 98.7" ==> 667/1000
"0.14 0.14 0.14 0.14 0.14 0.14 0.14 0.14 0.14 98.65" ==> 667/10000
"0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 97.8" ==> 401/500
"0.24 0.24 0.24 0.24 0.24 0.24 0.24 0.24 0.24 97.75" ==> 401/235
"0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 0.249377 97.75561" ==> 401/14010

puoi perdere 6 byte convertendoli Debug.Print inDebug.?
Taylor Scott

2

C # (.NET Core) , 286 byte

double M(string[]a){var p=a.Select(double.Parse).ToList();var n=p.Select(x=>1d).ToList();var c=2;for(;;){Func<double,double>f=x=>Math.Round(x*1000/c,(MidpointRounding)1)/10;if(n.Select(f).Zip(p,(x,y)=>x==y).All(z=>z)&&c==n.Sum())return c;c++;n=n.Zip(p,(x,y)=>x+(f(x)<y?1:0)).ToList();}}

Provalo online!

Salvataggio di molti byte grazie a Peter Taylor e Embodiment of Ignorance


Come posso modificarlo per testarlo su ideone.com?
Gareth,

Penso che ti manchi un }alla fine.
grc,

@Gareth Ho provato a eseguirlo su ideone.com, ma penso che stia utilizzando una versione di .NET framework precedente alla 4.0, perché non riconosce il Zipmetodo Linq .
Cristian Lupascu,

@grc Grazie per averlo sottolineato. Aggiornato.
Cristian Lupascu,

1
@Gaffi: No, C # ha una digitazione rigorosa (come Java), quindi deve essere un valore booleano. Poiché 1>0è più breve di true, è preferito.
mellamokb,

0

Python 3 , 140 139 137 byte

f=lambda l,m=1,i=0,c=0,x=0:round(x*100,1)-l[i]and(x<1and f(l,m,i,c,x+1/m)or f(l,m+1))or l[i+1:]and f(l,m,i+1,c+x)or c+x-1and f(l,m+1)or m

Provalo online!

Fornisce la risposta giusta per i primi due casi di test e si imbatte nei limiti di ricorsione di Python per gli altri. Questo non è molto sorprendente, da allora ogni controllo viene effettuato su un nuovo livello di ricorsione. È breve, però ...

(Una spiegazione delle variabili utilizzate è disponibile nel collegamento TIO)

f=lambda l,m=1,i=0,c=0,x=1:round(x*100,1)-l[i]and(x and f(l,m,i,c,x-1/m)or f(l,m+1))or l[i+1:]and f(l,m,i+1,c+x)or c+x-1and f(l,m+1)or m

dovrebbe funzionare per 136 byte, ma non a causa della precisione float.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.