Integer Percentify


21

Scrivi una funzione che accetta un elenco di numeri interi positivi e restituisce un elenco di numeri interi che si avvicinano alla percentuale del totale per il numero intero corrispondente nella stessa posizione.

Tutti i numeri interi nell'elenco di restituzione devono aggiungere esattamente fino a 100. Puoi supporre che la somma dei numeri interi passati sia maggiore di 0. Il modo in cui vuoi arrotondare o troncare i decimali dipende da te fintanto che ogni singolo numero intero risultante viene restituito in percentuale è disattivato di non più di 1 in entrambe le direzioni.

p([1,0,2])      ->  [33,0,67] or [34,0,66]
p([1000,1000])  ->  [50,50]
p([1,1,2,4])    ->  [12,12,25,51] or [13,12,25,50] or [12,13,25,50] or [12,12,26,50]
p([0,0,0,5,0])  ->  [0,0,0,100,0]

Questo è , quindi vince il codice più breve in byte!


Il nostro algoritmo deve essere deterministico? Deve sempre terminare entro un tempo limitato?
lirtosiast

Abbiamo già avuto qualche problema di arrotondamento simile ma più generale
edc65,

1
Vi suggerisco di aggiungere un altro banco di prova: p([2,2,2,2,2,3]). Ha molte possibili risposte legali, ma non tutte 2possono essere associate allo stesso valore. Questo elimina molti algoritmi troppo semplici che funzionano su tutti i precedenti casi di test perché l'arrotondamento non è troppo male.
Sophia Lechner,

4
Possibile p([1000,1000]) -> [49,51]?
l4m2

1
@ l4m2 Sembra sbagliato, ma entrambi i risultati sono spenti di 1 e non più, quindi segue le specifiche
edc65

Risposte:


20

Dyalog APL, 21 19 16 byte

+\⍣¯1∘⌊100×+\÷+/

Quanto sopra è un equivalente del treno di

{+\⍣¯1⌊100×+\⍵÷+/⍵}

Provalo online.

Come funziona

                 ⍝ Sample input: 1 1 2 4
           +\    ⍝ Cumulative sum of input. (1 2 4 8)
              +/ ⍝ Sum of input. (8)
             ÷   ⍝ Divide the first result by the second. (0.125 0.25 0.5 1)
       100×      ⍝ Multiply each quotient by 100. (12.5 25 50 100)
      ⌊          ⍝ Round the products down to the nearest integer... (12 25 50 100)
     ∘           ⍝ and ...
  ⍣¯1            ⍝ apply the inverse of...
+\               ⍝ the cumulative sum. (12 13 25 50)

9
Se solo Fermat avesse potuto prendere lezioni di golf da te.
Tessellating Heckler,

1
@TessellatingHeckler Vedo cosa hai fatto lì. Forse allora avrebbe abbastanza spazio ai margini per la sua prova. :)
mbomb007,

14

TI-BASIC, 26 23 16 byte

Per calcolatori serie TI-83 + / 84 +.

ΔList(augment({0},int(cumSum(ᴇ2Ans/sum(Ans

Grazie a @Dennis per un bellissimo algoritmo! Prendiamo la somma cumulativa dell'elenco dopo la conversione in percentuali, quindi piano, virate uno 0 in primo piano e prendiamo le differenze. ᴇ2è un byte più breve di 100.

Allo stesso numero di byte è:

ΔList(augment({0},int(cumSum(Ans/sum(Ans%

Curiosità: %è un token a due byte che moltiplica un numero per 0,01, ma non c'è modo di inserirlo nella calcolatrice! È necessario modificare la fonte all'esterno o utilizzare un programma di assemblaggio.

Vecchio codice:

int(ᴇ2Ans/sum(Ans
Ans+(ᴇ2-sum(Ans)≥cumSum(1 or Ans

La prima riga calcola tutte le percentuali pavimentate, quindi la seconda riga aggiunge 1 ai primi Nelementi, dove Nè la percentuale rimasta. cumSum(sta per "somma cumulativa".

Esempio con {1,1,2,4}:

          sum(Ans                  ; 8
int(ᴇ2Ans/                         ; {12,12,25,50}

                        1 or Ans   ; {1,1,1,1}
                 cumSum(           ; {1,2,3,4}
     ᴇ2-sum(Ans)                   ; 1
                ≥                  ; {1,0,0,0}
Ans+                               ; {13,12,25,50}

Non avremo N>dim([list], perché nessuna percentuale è diminuita di oltre 1 nel pavimento.


Non sono sicuro di come conti i byte qui, mi sembra terribilmente più lungo di 23
David Arenburg,

@DavidArenburg Questa è solo la forma leggibile dall'uomo. Tutti i token ( int(, sum(, Ans, ecc) occupano solo un byte.
Dennis,

4
+1 Questo è uno dei golf TI-BASIC più impressionanti che abbia mai visto su questo sito.
PhiNotPi

Thomas questa risposta è sbalorditiva!
DaveAlger,

Sei sicuro che non c'è modo di inserire il %simbolo? Avrei pensato che potesse essere trovato nel catalogo dei simboli ... Inoltre, dovrei uscire dalla mia TI-84 + Silver. Non lo uso da un po '. Block Dude è fantastico.
mbomb007,

7

CJam, 25 23 22 byte

{_:e2\:+f/_:+100-Xb.+}

Grazie a @ Sp3000 per 25 → 24.

Provalo online.

Come funziona

_                   e# Push a copy of the input.
 :e2                e# Apply e2 to each integer, i.e., multiply by 100.
    \               e# Swap the result with the original.
     :+             e# Add all integers from input.
       f/           e# Divide the product by the sum. (integer division)
        _:+         e# Push the sum of copy.
           100-     e# Subtract 100. Let's call the result d.
               Xb   e# Convert to base 1, i.e., push an array of |d| 1's.
                 .+ e# Vectorized sum; increment the first |d| integers.

5

Mathematica, 41 byte

(s=Floor[100#/Tr@#];s[[;;100-Tr@s]]++;s)&

Aspetta, cosa succede qui?
Seequ,

@Vediq L'algoritmo è come il vecchio codice nella risposta TI-BASIC. Calcola tutte le percentuali pavimentate, quindi aggiunge 1 ai primi Nelementi, dove Nè la percentuale rimasta.
alephalpha,

5

J (8,04 beta) , 59 byte (30 byte rubati)

Porta J letterale a 30 byte della risposta APL di Dennis :

    f=.3 :'+/\^:_1<.100*(+/\%+/)y'

    f 1 1 2 4
12 13 25 50

Risposta 59 byte, meglio che potrei fare da solo:

f=.3 :0
p=.<.100*y%+/y
r=.100-+/p
p+((r$1),(#p-r)$0)/:\:p
)

(Basato sul resto che deve andare ai valori più alti, non più di +1 ciascuno, diviso su più valori nel caso di un resto> 1 o un pareggio per il valore più alto).

per esempio

   f 1 0 2
33 0 67

   f 1000 1000
50 50

   f 1 1 2 4
12 12 25 51

   f 0 0 0 5 0
0 0 0 100 0

   f 16 16 16 16 16 16
17 17 17 17 16 16

   f 0 100 5 0 7 1
0 89 4 0 7 0

Spiegazione

  • f=.3 : 0 - 'f' è una variabile, che è un tipo di verbo (3), definito di seguito (: 0):
  • p=. variabile 'p', costruita da:
    • y è un elenco di numeri 1 0 2
    • +/y è '+' messo tra ogni valore '/', la somma dell'elenco 3
    • y % (+/y) sono i valori y originali divisi per la somma: 0.333333 0 0.666667
    • 100 * (y%+/y)è 100x quei valori: 33.33.. 0 0.66...per ottenere le percentuali.
    • <. (100*y%+/y) è l'operatore di piano applicato alle percentuali: 33 0 66
  • r=. variabile 'r', costruita da:
    • +/p è la somma delle percentuali minime: 99
    • 100 - (+/p) è 100: la somma o i punti percentuali rimanenti necessari per rendere le percentuali sommate a 100.
  • risultato, non memorizzato:
    • r $ 1 è un elenco di 1, a condizione che il numero di elementi che dobbiamo incrementare: 1 [1 1 ..]
    • #p è la lunghezza dell'elenco delle percentuali
    • (#p - r) è il conteggio degli articoli che non verranno incrementati
    • (#p-r) $ 0 è un elenco di 0 purché contino: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) è l'elenco 1s seguito dall'elenco 0s: 1 0 0
    • \: pè un elenco di indici da cui prendere pper metterlo in ordine decrescente.
    • /: (\:p)è un elenco di indici da cui prendere \:pper metterlo in ordine crescente
    • ((r$1),(#p-r)$0)/:\:psta prendendo gli elementi dal 1 1 0 0 .. .. list maschera e l'ordinamento così ci sono 1s nelle posizioni delle più grandi percentuali, uno per ogni numero abbiamo bisogno di minimo, e 0 per altri numeri: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p sono le percentuali + la maschera, per rendere l'elenco dei risultati che si somma al 100%, che è il valore restituito dalla funzione.

per esempio

33 0 66 sums to 99
100 - 99 = 1
1x1 , (3-1)x0 = 1, 0 0
sorted mask   = 0 0 1

33 0 66
 0 0  1
-------
33 0 67

e

  • ) fine della definizione.

Non ho molta esperienza con J; Non sarei troppo sorpreso se ci fosse una "lista di trasformazioni in percentuali del totale" e un modo più pulito per "incrementare n valori più grandi". (Questo è 11 byte in meno rispetto al mio primo tentativo).


1
Molto bello. Ho una soluzione Python ma è molto più lunga di questa. Bel lavoro!
DaveAlger,

1
Se non l'hai notato, le regole sono cambiate, quindi dovresti essere in grado di abbreviarlo notevolmente.
lirtosiast

@DaveAlger grazie! @ThomasKwa Ho notato, non sono sicuro che mi aiuti in modo considerevole: al primo tentativo riesco a ottenere -2 caratteri. Avrei bisogno di cambiare l' list[0:100-n] + list[:-100-n]approccio - e non ho pensato a un altro modo di affrontarlo.
TessellatingHeckler

4

JavaScript (ES6), 81 byte

a=>(e=0,a.map(c=>((e+=(f=c/a.reduce((c,d)=>c+d)*100)%1),f+(e>.999?(e--,1):0)|0)))

Quella condizione "deve essere uguale a 100" (piuttosto che arrotondare e sommare) ha quasi raddoppiato il mio codice (da 44 a 81). Il trucco era aggiungere un pot per i valori decimali che, una volta raggiunto 1, prende 1 da se stesso e lo aggiunge al numero corrente. Il problema quindi era rappresentato dai punti fluttuanti, il che significa che qualcosa come [1,1,1] lascia un resto di .9999999999999858. Quindi ho cambiato il controllo per essere maggiore di .999 e ho deciso di chiamarlo abbastanza preciso.


4

Haskell, 42 27 byte

p a=[div(100*x)$sum a|x<-a]

Praticamente il metodo banale in Haskell, con alcuni spazi rimossi per il golf.

Console (le parentesi incluse sono coerenti con l'esempio):

*Main> p([1,0,2])
[33,0,66]
*Main> p([1000,1000])
[50,50]
*Main> p([1,1,2,4])
[12,12,25,50]
*Main> p([0,0,0,5,0])
[0,0,0,100,0]

Modifica: praticato il mio mettere, fatto alcune ovvie sostituzioni.

Originale:

p xs=[div(x*100)tot|x<-xs]where tot=sum xs

1
La somma dell'elenco dovrebbe essere 100. Nel tuo primo esempio, è 99
Damien,

4

Gelatina , 7 byte

-2 grazie a Dennis, ricordandomi di usare un'altra nuova funzione ( Ä) e usando :invece quello che avevo inizialmente.

ŻÄ׳:SI

Provalo online!

Gelatina , 11 byte

0;+\÷S×ȷ2ḞI

Provalo online!

Fatto insieme a caird coinheringaahing e user202729 in chat .

Come funziona

0; + \ ÷ S × ȷ2ḞI - Programma completo.

0; - Prepara uno 0.
  + \ - Somma cumulativa.
    ÷ S - Diviso per la somma dell'ingresso.
      × ȷ2 - Times 100. Sostituito da × ³ nella versione monadica del collegamento.
         ḞI: ogni piano, calcola gli incrementi (delta, differenze).

3

Haskell, 63 56 55 byte

p l=tail>>=zipWith(-)$[100*x`div`sum l|x<-0:scanl1(+)l]

3

Perl, 42 byte

Basato sull'algoritmo di Dennis

Include +1 per -p

Esegui con l'elenco dei numeri su STDIN, ad es

perl -p percent.pl <<< "1 0 2"

percent.pl:

s%\d+%-$-+($-=$a+=$&*100/eval y/ /+/r)%eg


2

Python 2, 89 byte

def f(L):
 p=[int(x/0.01/sum(L))for x in L]
 for i in range(100-sum(p)):p[i]+=1
 return p

print f([16,16,16,16,16,16])
print f([1,0,2])

->

[17, 17, 17, 17, 16, 16]
[34, 0, 66]

2

Brain-Flak , 150 byte

((([]){[{}]({}<>)<>([])}{})[()])<>([]){{}<>([{}()]({}<([()])>)<>(((((({})({})({})){}){}){}{}){}){}(<()>))<>{(({}<({}())>)){({}[()])<>}{}}{}([])}<>{}{}

Provalo online!

A partire dalla fine e lavorando all'indietro, questo codice assicura ad ogni passo che la somma dei numeri di output finora è uguale alla percentuale totale riscontrata, arrotondata per difetto.

(

  # Compute and push sum of numbers
  (([]){[{}]({}<>)<>([])}{})

# And push sum-1 above it (simulating a zero result from the mod function)
[()])

<>

# While elements remain
([]){{}

  # Finish computation of modulo from previous step
  <>([{}()]({}

    # Push -1 below sum (initial value of quotient in divmod)
    <([()])>

  # Add to 100*current number, and push zero below it
  )<>(((((({})({})({})){}){}){}{}){}){}(<()>))

  # Compute divmod
  <>{(({}<({}())>)){({}[()])<>}{}}{}

([])}

# Move to result stack and remove values left over from mod
<>{}{}

2

JavaScript (ES6) 60 63 95

Adattato e semplificato dalla mia (sbagliata) risposta a un'altra sfida
Grazie a @ l4m2 per scoprire che anche questo era sbagliato

Risolto il problema con il salvataggio di 1 byte (e 2 byte in meno, senza contare il nome F=)

v=>v.map(x=>(x=r+x*100,r=x%f,x/f|0),f=eval(v.join`+`),r=f/2)

Prova a eseguire lo snippet di seguito in qualsiasi browser compatibile con EcmaScript 6

F=
v=>v.map(x=>(x=r+x*100,r=x%f,x/f|0),f=eval(v.join`+`),r=f/2)

console.log('[1,0,2] (exp [33,0,67] [34,0,66])-> '+F([1,0,2]))
console.log('[1000,1000] (exp [50,50])-> '+F([1000,1000]))
console.log('[1,1,2,4] (exp[12,12,25,51] [13,12,25,50] [12,13,25,50] [12,12,26,50])-> '+F([1,1,2,4]))
console.log('[0,0,0,5,0] (exp [0,0,0,100,0])-> '+F([0,0,0,5,0]))
console.log('[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980] -> '+F([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]))
console.log('[2,2,2,2,2,3] -> ' + F([2,2,2,2,2,3]))
<pre id=O></pre>


Errore[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
l4m2,

@ l4m2 non riuscito perché? La somma è 100 edany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65,

L'ultimo dovrebbe essere al massimo uno su 98, ma è 100
l4m2

@ l4m2 uh, giusto, grazie. Tempo di ripensarci
edc65

@ l4m2 dovrebbe essere risolto ora
edc65

1

Ruggine, 85 byte

Questo utilizza vettori invece di array perché, per quanto ne so, non c'è modo di accettare array di più lunghezze diverse.

let a=|c:Vec<_>|c.iter().map(|m|m*100/c.iter().fold(0,|a,x|a+x)).collect::<Vec<_>>();

1

JavaScript, 48 byte

F=

x=>x.map(t=>s+=t,y=s=0).map(t=>-y+(y=100*t/s|0))

// Test 
console.log=x=>O.innerHTML+=x+'\n';


console.log('[1,0,2] (exp [33,0,67] [34,0,66])-> '+F([1,0,2]))
console.log('[1000,1000] (exp [50,50])-> '+F([1000,1000]))
console.log('[1,1,2,4] (exp[12,12,25,51] [13,12,25,50] [12,13,25,50] [12,12,26,50])-> '+F([1,1,2,4]))
console.log('[0,0,0,5,0] (exp [0,0,0,100,0])-> '+F([0,0,0,5,0]))
<pre id=O></pre>


0

Jq 1,5 , 46 byte

add as$s|.[1:]|map(100*./$s|floor)|[100-add]+.

allargato

  add as $s               # compute sum of array elements
| .[1:]                   # \ compute percentage for all elements 
| map(100*./$s|floor)     # / after the first element
| [100-add] + .           # compute first element as remaining percentage

Provalo online!


0

PHP, 82 byte

for(;++$i<$argc-1;$s+=$x)echo$x=$argv[$i]/array_sum($argv)*100+.5|0,_;echo 100-$s;

accetta input dagli argomenti della riga di comando, stampa le percentuali delimitate da trattino basso.

Corri con -nro provalo online .


Questo emette 15_15_15_15_15_25quando viene fornito l'input [2,2,2,2,3], il che non è corretto perché3/13 ~= 23.1%
Sophia Lechner,

@SophiaLechner Quale delle risposte lo fa correttamente?
Tito,

Molti lo fanno, in realtà. Le risposte corrette finora sembrano essere costruite attorno a uno dei due algoritmi; il primo completa le percentuali delle somme cumulative e prende la differenza; la seconda calcola i piani delle percentuali e quindi incrementa abbastanza percentuali distinte per portare il totale a 100.
Sophia Lechner,

@SophiaLechner Non intendevo dire che non avrei esaminato; ma lo farò più tardi. Grazie per averlo notato.
Tito,
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.