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.