Porcentagem de número inteiro


21

Escreva uma função que inclua uma lista de números inteiros positivos e retorne uma lista de números inteiros aproximando a porcentagem do total para o número inteiro correspondente na mesma posição.

Todos os números inteiros na lista de retorno devem adicionar exatamente até 100. Você pode assumir que a soma dos números inteiros passados ​​é maior que 0. Como você deseja arredondar ou truncar decimais, é com você, desde que qualquer número inteiro resultante retorne como porcentagem está desativado em não mais que 1 em qualquer direção.

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]

Isso é , então o código mais curto em bytes vence!


Nosso algoritmo deve ser determinístico? Ele deve sempre terminar dentro de um tempo limitado?
— Lirtosiast

Já teve algum problema de arredondamento semelhante, mas mais geral
— edc65

11
Eu sugiro que você adicionar outro caso de teste: p([2,2,2,2,2,3]). Tem muitas respostas legais possíveis, mas nem todas 2podem ser mapeadas para o mesmo valor. Isso elimina muitos algoritmos excessivamente simples que funcionam em todos os casos de teste anteriores porque o arredondamento não é muito ruim.
— Sophia Lechner

4
Pode p([1000,1000]) -> [49,51]?
— L4m2

11
@ l4m2 Parece errado, mas ambos os resultados estão fora de 1 e não mais, portanto segue a especificação
— edc65 19/18/18

Respostas:


20

Dyalog APL, 21 19 16 bytes

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

O acima é um trem equivalente a

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

Experimente online.

Como funciona

                 ⍝ 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 apenas Fermat pudesse ter tido aulas de golfe com você.
— TessellatingHeckler

11
@TessellatingHeckler Eu vejo o que você fez lá. Talvez então ele tivesse espaço suficiente nas margens para sua prova. :)
— mbomb007

14

TI-BASIC, 26 23 16 bytes

Para calculadoras da série TI-83 + / 84 +.

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

Obrigado a @Dennis por um belo algoritmo! Pegamos a soma cumulativa da lista depois de converter em porcentagem, depois andar, colocar um 0 na frente e fazer as diferenças. ᴇ2é um byte menor que 100.

Na mesma contagem de bytes é:

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

Curiosidade: %é um token de dois bytes que multiplica um número por 0,01 - mas não há como digitá-lo na calculadora! Você precisa editar a fonte fora ou usar um programa de montagem.

Código antigo:

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

A primeira linha calcula todas as porcentagens pavimentadas e, em seguida, a segunda linha adiciona 1 aos primeiros Nelementos, onde Né a porcentagem restante. cumSum(significa "soma acumulada".

Exemplo com {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}

Não teremos N>dim([list], porque nenhuma porcentagem diminui em mais de 1 no piso.


Não tenho certeza como você contar os bytes aqui, ele parece muito mais longo do que 23 para mim
— David Arenburg

@DavidArenburg Esta é apenas a forma legível por humanos. Todos os símbolos ( int(, sum(, Ans, etc.) ocupar somente um byte.
— Dennis

4
+1 Este é um dos mais impressionantes campos de golfe da TI que eu já vi neste site.
— PhiNotPi

Thomas, esta resposta é impressionante!
— DaveAlger

Tem certeza de que não há como inserir o %símbolo? Eu pensei que poderia ser encontrado no catálogo de símbolos ... Além disso, eu deveria pegar minha TI-84 + Silver. Eu não uso há um tempo. Block Dude é incrível.
— mbomb007

7

CJam, 25 23 22 bytes

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

Obrigado a @ Sp3000 por 25 → 24.

Experimente online.

Como funciona

_                   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 bytes

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

Espere, o que acontece aqui?
— 8/15

@Seeq O algoritmo é como o código antigo na resposta do TI-BASIC. Ele calcula todas as porcentagens pavimentadas e adiciona 1 aos primeiros Nelementos, onde Nfica a porcentagem restante.
— Alephalpha #

5

J (8,04 beta) , 59 bytes (30 bytes roubados)

Porta J literal de 30 bytes da resposta APL de Dennis :

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

    f 1 1 2 4
12 13 25 50

59 bytes de resposta, o melhor que eu poderia fazer:

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

(Com base no restante dos valores mais altos, no máximo +1), divida-os em vários valores no caso de um restante> 1 ou um empate para o valor mais alto).

por exemplo

   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

Explicação

  • f=.3 : 0 - 'f' é uma variável, que é um tipo de verbo (3), definido abaixo (: 0):
  • p=. variável 'p', criada a partir de:
    • y é uma lista de números 1 0 2
    • +/y é '+' colocado entre cada valor '/', a soma da lista 3
    • y % (+/y) são os valores y originais divididos pela soma: 0.333333 0 0.666667
    • 100 * (y%+/y)é 100x esses valores: 33.33.. 0 0.66...para obter as porcentagens.
    • <. (100*y%+/y) é o operador de piso aplicado às porcentagens: 33 0 66
  • r=. variável 'r', criada a partir de:
    • +/p é a soma das porcentagens com piso: 99
    • 100 - (+/p) é 100 - a soma ou os pontos percentuais restantes necessários para fazer com que as porcentagens totalizem 100.
  • resultado, não armazenado:
    • r $ 1 é uma lista de 1s, contanto que o número de itens que precisamos incrementar: 1 [1 1 ..]
    • #p é o comprimento da lista de porcentagem
    • (#p - r) é a contagem de itens que não serão incrementados
    • (#p-r) $ 0 é uma lista de 0s, desde que contados: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) é a lista 1s seguida pela lista 0s: 1 0 0
    • \: pé uma lista de índices para extrair pe colocar em ordem decrescente.
    • /: (\:p)é uma lista de índices a serem tirados \:ppara colocar em ordem crescente
    • ((r$1),(#p-r)$0)/:\:pestá tomando os elementos do 1 1 .. 0 0 .. lista máscara e classificar de forma que há 1s nas posições dos maiores percentagens, um para cada número precisamos incremento, e 0s para outros números: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p são as porcentagens + a máscara, para fazer a lista de resultados que totaliza 100%, que é o valor de retorno da função.

por exemplo

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

  • ) fim de definição.

Eu não sou muito experiente com J; Eu não ficaria surpreso se houver uma "lista de transformar-se em percentagens do total", operação integrada, e uma maneira mais limpa para "incremento n maiores valores" também. (Isso é 11 bytes a menos que minha primeira tentativa).


11
Muito legal. Eu tenho uma solução python, mas é muito mais longa que esta. Bom trabalho!
— DaveAlger

11
Se você não percebeu, as regras foram alteradas; portanto, você poderá reduzi-lo consideravelmente.
— lirtosiast

@DaveAlger thanks! @ThomasKwa Notei, não tenho certeza se isso me ajuda consideravelmente - na primeira tentativa, consigo -2 caracteres. Eu precisaria mudar a list[0:100-n] + list[:-100-n]abordagem - e não pensei em outra maneira de abordá-la.
— TessellatingHeckler

4

JavaScript (ES6), 81 bytes

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

Essa condição "deve ser igual a 100" (em vez de arredondar e somar) quase dobrou meu código (de 44 para 81). O truque era adicionar um pote para valores decimais que, uma vez atingido 1, retira 1 de si e o adiciona ao número atual. O problema então era pontos flutuantes, o que significa que algo como [1,1,1] deixa um restante de .9999999999999858. Então, mudei o cheque para mais de 0,999 e decidi chamar isso de preciso o suficiente.


4

Haskell, 42 27 bytes

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

Praticamente o método trivial em Haskell, com alguns espaços removidos para jogar golfe.

Console (colchetes incluídos para serem consistentes com o exemplo):

*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]

Edit: praticou minha colocação, fez algumas substituições óbvias.

Original:

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

11
A soma da lista deve ser 100. No seu primeiro exemplo, é 99
— Damien

4

Jelly , 7 bytes

-2 graças a Dennis, lembrando-me de usar outro novo recurso ( Ä) e usar em :vez do que eu tinha inicialmente.

ŻÄ׳:SI

Experimente online!

Gelatina , 11 bytes

0;+\÷S×ȷ2ḞI

Experimente online!

Feito ao lado de caird coinheringaahing e user202729 no chat .

Como funciona

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

0; - Anexe um 0.
  + \ - Soma acumulada.
    ÷ S - Dividido pela soma da entrada.
      × ȷ2 - Vezes 100. Substituído por × ³ na versão do link monádico.
         ḞI - Pavimente cada um, calcule os incrementos (deltas, diferenças).

3

Haskell, 63 56 55 bytes

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

3

Perl, 42 bytes

Baseado no algoritmo de Dennis

Inclui +1 para -p

Corra com a lista de números no STDIN, por exemplo

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

percent.pl:

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

2

Oitava, 40 bytes

@(x)diff(ceil([0,cumsum(100*x/sum(x))]))

2

Python 2, 89 bytes

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

Flacidez cerebral , 150 bytes

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

Experimente online!

Começando pelo final e trabalhando para trás, esse código garante a cada etapa que a soma dos números de saída até agora é igual à porcentagem total encontrada, arredondada para baixo.

(

  # 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

Adaptado e simplificado da minha resposta (errada) para outro desafio
Thk para @ l4m2 por descobrir que isso também estava errado

Corrigido o salvamento de 1 byte (e 2 bytes a menos, sem contar o nome F=)

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

Teste a execução do snippet abaixo em qualquer navegador compatível com 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>


Falha ao ligar[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
— l4m2

@ l4m2 falhou por quê? A soma é 100 eany single resulting integer returned as a percentage is off by no more than 1 in either direction.
— edc65

O último deve ser no máximo um por 98, mas é 100
— l4m2

@ l4m2 uh, certo, thanks.Time pensar novamente
— edc65

@ l4m2 deve ser corrigido agora
— edc65

1

Ferrugem, 85 bytes

Isso usa vetores em vez de matrizes porque, até onde sei, não há como aceitar matrizes de vários comprimentos diferentes.

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

1

JavaScript, 48 bytes

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 bytes

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

Expandido

  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

Experimente online!


0

PHP, 82 bytes

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

recebe entrada dos argumentos da linha de comando, imprime porcentagens delimitadas por sublinhado.

Corra com -nrou experimente online .


Isso gera 15_15_15_15_15_25quando dada a entrada [2,2,2,2,3], o que não é certo, porque3/13 ~= 23.1%
— Sophia Lechner

@SophiaLechner Qual das respostas faz isso corretamente?
— Titus

A maioria faz, na verdade. As respostas corretas até agora parecem ser construídas em torno de um dos dois algoritmos; o primeiro arredonda as porcentagens de somas acumuladas e leva a diferença; o segundo calcula os pisos dos percentuais e, em seguida, incrementa porcentagens distintas suficientes para trazer o total para 100.
— Sophia Lechner

@SophiaLechner Eu não quis dizer que não iria investigar; mas eu vou fazer depois. Obrigado por perceber.
— Titus
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.