Entero Percentificar


21

Escriba una función que tome una lista de enteros positivos y devuelva una lista de enteros que se aproxima al porcentaje del total para el entero correspondiente en la misma posición.

Todos los enteros en la lista de retorno deben sumar exactamente 100. Puede suponer que la suma de los enteros pasados ​​es mayor que 0. La forma en que desea redondear o truncar decimales depende de usted siempre que cualquier entero resultante devuelto como un porcentaje está desactivado por no más de 1 en cualquier dirección.

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]

Este es el , por lo que gana el código más corto en bytes.


¿Debe nuestro algoritmo ser determinista? ¿Debe terminar siempre dentro de un tiempo limitado?
lirtosiast

Ya tuvimos un problema de redondeo similar pero más general
edc65

1
Sugiero que se agrega otro caso de prueba: p([2,2,2,2,2,3]). Tiene muchas respuestas legales posibles, pero no todas 2pueden asignarse al mismo valor. Esto elimina muchos algoritmos demasiado simples que funcionan en todos los casos de prueba anteriores porque el redondeo no es tan malo.
Sophia Lechner

44
Puede p([1000,1000]) -> [49,51]?
l4m2

1
@ l4m2 Parece incorrecto, pero ambos resultados están desactivados en 1 y no más, por lo que sigue las especificaciones
edc65

Respuestas:


20

Dyalog APL, 21 19 16 bytes

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

Lo anterior es un tren equivalente a

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

Pruébalo en línea.

Cómo 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)

99
Si tan solo Fermat pudiera haber tomado lecciones de golf tuyas.
TessellatingHeckler

1
@TessellatingHeckler Veo lo que hiciste allí. Tal vez entonces tendría suficiente espacio en los márgenes para su prueba. :)
mbomb007

14

TI-BASIC, 26 23 16 bytes

Para calculadoras de la serie TI-83 + / 84 +.

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

¡Gracias a @Dennis por un hermoso algoritmo! Tomamos la suma acumulativa de la lista después de convertir a porcentajes, luego piso, agregamos un 0 al frente y tomamos las diferencias. ᴇ2es un byte más corto que 100.

En el mismo número de bytes es:

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

Dato curioso: %es un token de dos bytes que multiplica un número por .01, ¡pero no hay forma de escribirlo en la calculadora! Debe editar la fuente externa o usar un programa de ensamblaje.

Código antiguo

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

La primera línea calcula todos los porcentajes del piso, luego la segunda línea suma 1 a los primeros Nelementos, donde Nes el porcentaje restante. cumSum(significa "suma acumulativa".

Ejemplo 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}

No lo haremos N>dim([list], porque ningún porcentaje se reduce en más de 1 en el piso.


No estoy seguro de cómo contar los bytes aquí, me parece terriblemente más largo que 23
David Arenburg

@DavidArenburg Esta es solo la forma legible por humanos. Todas las fichas ( int(, sum(, Ans, etc.) ocupan sólo un byte.
Dennis

44
+1 Este es uno de los campos de golf TI-BASIC más impresionantes que he visto en este sitio.
PhiNotPi

Thomas esta respuesta es impresionante!
DaveAlger

¿Estás seguro de que no hay forma de ingresar el %símbolo? Pensé que podría encontrarse en el catálogo de símbolos ... Además, debería sacar mi TI-84 + Silver. No lo he usado en mucho tiempo. Block Dude es asombroso.
mbomb007

7

CJam, 25 23 22 bytes

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

Gracias a @ Sp3000 por 25 → 24.

Pruébalo en línea.

Cómo 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)&

Espera, ¿qué pasa aquí?
seequ

@Seeq El algoritmo es como el código anterior en la respuesta de TI-BASIC. Calcula todos los porcentajes de piso, luego agrega 1 a los primeros Nelementos, donde Nes el porcentaje restante.
alephalpha

5

J (8.04 beta) , 59 bytes (30 bytes robados)

Puerto J literal de 30 bytes de la respuesta APL de Dennis :

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

    f 1 1 2 4
12 13 25 50

Respuesta de 59 bytes, lo mejor que pude hacer yo mismo:

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

(Basado en que el resto tiene que ir a los valores más altos, no más de +1 cada uno, dividido en múltiples valores en el caso de un resto> 1 o un empate para el valor más alto).

p.ej

   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

Explicación

  • f=.3 : 0 - 'f' es una variable, que es un tipo de verbo (3), definido a continuación (: 0):
  • p=. variable 'p', construida a partir de:
    • y es una lista de números 1 0 2
    • +/y es '+' puesto entre cada valor '/', la suma de la lista 3
    • y % (+/y) son los valores originales y divididos por la suma: 0.333333 0 0.666667
    • 100 * (y%+/y)es 100x esos valores: 33.33.. 0 0.66...para obtener los porcentajes.
    • <. (100*y%+/y) es el operador de piso aplicado a los porcentajes: 33 0 66
  • r=. variable 'r', construida a partir de:
    • +/p es la suma de los porcentajes en pisos: 99
    • 100 - (+/p) es 100: la suma o los puntos porcentuales restantes necesarios para hacer que los porcentajes sumen 100.
  • resultado, no almacenado:
    • r $ 1 es una lista de 1s, siempre que la cantidad de elementos que necesitemos incrementar: 1 [1 1 ..]
    • #p es la longitud de la lista de porcentajes
    • (#p - r) es el recuento de elementos que no se incrementarán
    • (#p-r) $ 0 es una lista de 0 siempre que eso cuente: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) es la lista de 1 seguida de la lista de 0: 1 0 0
    • \: pes una lista de índices para tomar ppara ponerlo en orden descendente.
    • /: (\:p)es una lista de índices para tomar \:ppara poner eso en orden ascendente
    • ((r$1),(#p-r)$0)/:\:pse está llevando a los elementos de la 1 1 0 0 .. .. lista de máscara y la clasificación por lo que hay 1s en las posiciones de los mayores porcentajes, uno para cada número que necesitamos para la subasta, y 0s para otros números: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p son los porcentajes + la máscara, para hacer la lista de resultados que suma al 100%, que es el valor de retorno de la función.

p.ej

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

y

  • ) Fin de la definición.

No tengo mucha experiencia con J; No me sorprendería demasiado si hay una "lista de conversión en porcentajes del total" integrada, y una forma más limpia de "incrementar n valores más grandes" también. (Esto es 11 bytes menos que mi primer intento).


1
Muy genial. Tengo una solución de Python, pero es mucho más larga que esta. ¡Buen trabajo!
DaveAlger

1
Si no lo has notado, las reglas han cambiado, por lo que deberías poder acortar esto considerablemente.
lirtosiast

@DaveAlger gracias! @ThomasKwa Me di cuenta, no estoy seguro de que me ayude considerablemente: en el primer intento puedo obtener -2 caracteres. Necesitaría cambiar el list[0:100-n] + list[:-100-n]enfoque, y no he pensado en otra forma de abordarlo.
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)))

Esa condición "debe ser igual a 100" (en lugar de redondear y sumar) casi duplicó mi código (de 44 a 81). El truco consistía en agregar un bote para valores decimales que, una vez que alcanza 1, toma 1 de sí mismo y lo agrega al número actual. El problema era, entonces, los puntos flotantes, lo que significa que algo así como [1,1,1] deja un resto de .9999999999999858. Así que cambié el cheque para que sea mayor que .999, y decidí llamarlo lo suficientemente preciso.


4

Haskell, 42 27 bytes

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

Prácticamente el método trivial en Haskell, con algunos espacios eliminados para jugar al golf.

Consola (se incluyen soportes para ser coherentes con el ejemplo):

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

Editar: practiqué mi colocación, hice algunos reemplazos obvios.

Original:

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

1
La suma de la lista debe ser 100. En su primer ejemplo, es 99
Damien

4

Jalea , 7 bytes

-2 gracias a Dennis, recordándome que use otra función nueva ( Ä) y usando en :lugar de lo que tenía inicialmente.

ŻÄ׳:SI

Pruébalo en línea!

Jalea , 11 bytes

0;+\÷S×ȷ2ḞI

Pruébalo en línea!

Hecho junto a caird coinheringaahing y user202729 en el chat .

Cómo funciona

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

0; - Anteponer un 0.
  + \ - Suma acumulativa.
    ÷ S - Dividido por la suma de la entrada.
      × ȷ2 - Veces 100. Reemplazado por × ³ en la versión de enlace monádico.
         ḞI - Piso cada uno, calcular los incrementos (deltas, diferencias).

3

Haskell, 63 56 55 bytes

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

3

Perl, 42 bytes

Basado en el algoritmo de Dennis

Incluye +1 para -p

Ejecutar con la lista de números en STDIN, p. Ej.

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

percent.pl:

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


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

Brain-Flak , 150 bytes

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

Pruébalo en línea!

Comenzando desde el final y trabajando hacia atrás, este código asegura en cada paso que la suma de los números de salida hasta ahora es igual al porcentaje total encontrado, redondeado hacia abajo.

(

  # 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 y simplificado de mi respuesta (incorrecta) a otro desafío
Thk a @ l4m2 por descubrir que esto también estaba mal

Se arregló el ahorro de 1 byte (y 2 byte menos, sin contar el nombre F=)

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

Pruebe a ejecutar el fragmento a continuación en cualquier navegador compatible 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>


Falló el [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
l4m2

@ l4m2 falló ¿por qué? La suma es 100 yany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65

El último debería ser como máximo uno por 98, pero es 100
l4m2

@ l4m2 uh, cierto, gracias. Es hora de pensar de nuevo
edc65

@ l4m2 debería arreglarse ahora
edc65

1

Óxido, 85 bytes

Esto usa vectores en lugar de matrices porque, hasta donde yo sé, no hay forma de aceptar matrices de múltiples longitudes 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

Pruébalo en línea!


0

PHP, 82 bytes

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

toma datos de los argumentos de la línea de comandos, imprime porcentajes delimitados por guiones bajos.

Ejecutar -nro probarlo en línea .


Esto sale 15_15_15_15_15_25cuando se le da la entrada [2,2,2,2,3], lo cual no está bien porque3/13 ~= 23.1%
Sophia Lechner

@SophiaLechner ¿Cuál de las respuestas hace eso correctamente?
Titus

La mayoría lo hace, en realidad. Las respuestas correctas hasta ahora parecen estar construidas alrededor de uno de dos algoritmos; el primero completa los porcentajes de sumas acumuladas y toma la diferencia; el segundo calcula los pisos de los porcentajes y luego incrementa suficientes porcentajes distintos para llevar el total a 100.
Sophia Lechner

@SophiaLechner No quise decir que no lo investigaría; pero lo haré luego. Gracias por notarlo.
Titus
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.