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.