Integer Percentify

21

Schreiben Sie eine Funktion, die eine Liste positiver Ganzzahlen aufnimmt und eine Liste von Ganzzahlen zurückgibt, die in etwa dem Prozentsatz der Summe für die entsprechende Ganzzahl an derselben Position entspricht.

Alle Ganzzahlen in der Rückgabeliste müssen genau 100 ergeben. Sie können davon ausgehen, dass die Summe der übergebenen Ganzzahlen größer als 0 ist. Wie Sie Dezimalzahlen runden oder abschneiden möchten, bleibt Ihnen überlassen, solange eine einzelne resultierende Ganzzahl als Prozentsatz zurückgegeben wird ist um nicht mehr als 1 in beide Richtungen ausgeschaltet.

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]

Das ist , also gewinnt der kürzeste Code in Bytes!

DaveAlger
quelle
Muss unser Algorithmus deterministisch sein? Muss es immer innerhalb einer begrenzten Zeit enden?
Lirtosiast
Wir hatten bereits ein Rundungsproblem ähnlich, aber allgemeiner
edc65 10.10.15
1
Ich schlage vor , dass Sie einen anderen Testfall hinzu: p([2,2,2,2,2,3]). Es gibt viele mögliche rechtliche Antworten, aber nicht alle 2können auf den gleichen Wert abgebildet werden. Dadurch entfallen viele zu einfache Algorithmen, die für alle vorherigen Testfälle verwendet werden, da die Rundung nicht allzu schlecht ist.
Sophia Lechner
4
Können p([1000,1000]) -> [49,51]?
14.
1
beide @ l4m2 Es scheint falsch, aber die Ergebnisse sind aus von 1 und nicht mehr, so dass es die Spezifikation folgt
edc65

Antworten:

20

Dyalog APL, 21 19 16 Bytes

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

Das obige ist ein Zugäquivalent von

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

Probieren Sie es online aus.

Wie es funktioniert

                 ⍝ 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)
Dennis
quelle
9
Wenn Fermat nur Golfunterricht von Ihnen hätte nehmen können.
TessellatingHeckler
1
@TessellatingHeckler Ich sehe was du da gemacht hast. Vielleicht hätte er dann genug Platz am Rand für seinen Beweis. :)
mbomb007
14

TI-BASIC, 26 23 16 Bytes

Für Taschenrechner der Serie TI-83 + / 84 +.

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

Vielen Dank an @Dennis für einen schönen Algorithmus! Wir nehmen die kumulative Summe der Liste, nachdem wir in Prozent konvertiert haben, dann Floor, setzen eine 0 auf die Front und nehmen Differenzen auf. ᴇ2ist ein Byte kürzer als 100.

Gleichzeitig ist die Byteanzahl:

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

Unterhaltsame Tatsache: %ist ein Zwei-Byte-Token , das eine Zahl mit 0,01 multipliziert - aber es gibt keine Möglichkeit, sie in den Taschenrechner einzugeben! Sie müssen entweder die Quelle außerhalb bearbeiten oder ein Assembly-Programm verwenden.

Alter Code:

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

In der ersten Zeile werden alle Prozentsätze für den Fußboden berechnet. In der zweiten Zeile wird 1 zu den ersten NElementen hinzugefügt, wobei Nder verbleibende Prozentsatz angegeben wird. cumSum(steht für "kumulative Summe".

Beispiel mit {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}

Wir werden nicht haben N>dim([list], weil kein Prozentsatz in Bodenbelägen um mehr als 1 verringert wird.

Lirtosiast
quelle
Nicht sicher, wie Sie die Bytes hier zählen, es sieht schrecklich länger als 23 für mich
David Arenburg
@ DavidArenburg Dies ist nur die für Menschen lesbare Form. Alle Token ( int(, sum(, Ans, etc.) belegen nur ein Byte.
Dennis
4
+1 Dies ist einer der beeindruckendsten TI-BASIC-Golfplätze, die ich auf dieser Website gesehen habe.
PhiNotPi
Thomas diese antwort ist umwerfend!
DaveAlger
Sind Sie sicher, dass Sie das %Symbol nicht eingeben können ? Ich hätte gedacht, dass es im Symbolkatalog zu finden ist ... Außerdem sollte ich meinen TI-84 + Silver herausholen. Ich habe es eine Weile nicht mehr benutzt. Block Dude ist großartig.
mbomb007
7

CJam, 25 23 22 Bytes

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

Vielen Dank an @ Sp3000 für 25 → 24.

Probieren Sie es online aus.

Wie es funktioniert

_                   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.
Dennis
quelle
5

Mathematica, 41 Bytes

(s=Floor[100#/Tr@#];s[[;;100-Tr@s]]++;s)&
Alephalpha
quelle
Warten Sie, was passiert hier?
Siehe auch
@Seeq Der Algorithmus ist wie der alte Code in der TI-BASIC-Antwort. Es berechnet alle Prozentsätze für den Fußboden und addiert dann 1 zu den ersten NElementen, wobei Nder verbleibende Prozentsatz ist.
alephalpha
5

J (8.04 Beta) , 59 Bytes (30 gestohlene Bytes)

30-Byte-Literal-J-Port von Dennis 'APL-Antwort :

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

    f 1 1 2 4
12 13 25 50

59 Bytes antworten, am besten ich könnte mich selbst tun:

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

(Bezogen auf den Rest, der zu den höchsten Werten gehen muss, jeweils nicht mehr als +1, aufgeteilt auf mehrere Werte bei einem Rest> 1 oder einem Gleichstand für den höchsten Wert).

z.B

   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

Erläuterung

  • f=.3 : 0 - 'f' ist eine Variable, bei der es sich um einen Verbtyp (3) handelt, der unten definiert ist (: 0):
  • p=. Variable 'p', aufgebaut aus:
    • y ist eine Liste von Zahlen 1 0 2
    • +/y wird '+' zwischen jeden Wert '/' gesetzt, die Summe der Liste 3
    • y % (+/y) ist der ursprüngliche y-Wert geteilt durch die Summe: 0.333333 0 0.666667
    • 100 * (y%+/y)ist das 100-fache dieser Werte: 33.33.. 0 0.66...um die Prozentsätze zu erhalten.
    • <. (100*y%+/y) Wird der Fußbodenoperator auf die Prozentsätze angewendet: 33 0 66
  • r=. Variable 'r', aufgebaut aus:
    • +/p ist die Summe der Floored-Prozentsätze: 99
    • 100 - (+/p) ist 100 - die Summe oder die verbleibenden Prozentpunkte, die benötigt werden, um die Prozentzahlen auf 100 zu summieren.
  • Ergebnis, nicht gespeichert:
    • r $ 1 ist eine Liste von 1s, solange die Anzahl der Elemente erhöht werden muss: 1 [1 1 ..]
    • #p ist die Länge der Prozentliste
    • (#p - r) ist die Anzahl der Elemente, die nicht erhöht werden
    • (#p-r) $ 0 ist eine Liste von Nullen, solange diese zählen: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) ist die Liste der Einsen, gefolgt von der Liste der Nullen: 1 0 0
    • \: pist eine Liste von Indizes, aus denen pSie absteigend sortieren können.
    • /: (\:p)ist eine Liste von Indizes, aus \:pdenen Sie aufsteigend sortieren können
    • ((r$1),(#p-r)$0)/:\:pdie Elemente aus den 1 1 .. 0 0 .. Maske Liste nehme und Sortier so gibt es 1s in den Positionen der größten Prozentsatz, eines für jede Zahl , die wir zu Schritt benötigen, und 0er für andere Zahlen: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p ist der Prozentsatz + die Maske, um die Ergebnisliste zu erstellen, die sich zu 100% summiert. Dies ist der Rückgabewert der Funktion.

z.B

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

und

  • ) Ende der Definition.

Ich bin nicht sehr erfahren mit J; Es würde mich nicht überraschen, wenn eine "Liste in Prozent der Gesamtmenge umwandeln" -Operation eingebaut wäre und eine sauberere Methode, um " n größte Werte zu erhöhen". (Das sind 11 Bytes weniger als mein erster Versuch).

TessellatingHeckler
quelle
1
Sehr cool. Ich habe eine Python-Lösung, aber sie ist viel länger als diese. Gute Arbeit!
DaveAlger
1
Wenn Sie es nicht bemerkt haben, haben sich die Regeln geändert, so dass Sie dies erheblich verkürzen können sollten.
Lirtosiast
@ DaveAlger danke! @ThomasKwa Mir ist aufgefallen, dass es mir nicht wirklich weiterhilft - beim ersten Versuch kann ich -2 Zeichen bekommen. Ich müsste die list[0:100-n] + list[:-100-n]Herangehensweise ändern - und ich habe mir keine andere Herangehensweise überlegt.
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)))

Die Bedingung "Muss gleich 100" (anstatt zu runden und zu addieren) hat meinen Code fast verdoppelt (von 44 auf 81). Der Trick bestand darin, einen Pot für Dezimalwerte hinzuzufügen, der, sobald er 1 erreicht, 1 von sich nimmt und zur aktuellen Zahl hinzufügt. Das Problem waren dann Gleitkommazahlen, was bedeutet, dass so etwas wie [1,1,1] einen Rest von .9999999999999858 hinterlässt. Also habe ich den Scheck auf über 0,999 geändert und mich dazu entschlossen, das genau genug zu nennen.

Mwr247
quelle
4

Haskell, 42 27 Bytes

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

Ziemlich die triviale Methode in Haskell, mit ein paar Räumen zum Golfen entfernt.

Konsole (Klammern enthalten, um mit Beispiel übereinzustimmen):

*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: übte mein Putten, machte einige offensichtliche Ersetzungen.

Original:

p xs=[div(x*100)tot|x<-xs]where tot=sum xs
Jake
quelle
1
Die Summe der Liste sollte 100 sein. In Ihrem ersten Beispiel ist es 99
Damien
4

Gelee , 7 Bytes

-2 Dank an Dennis, der mich daran erinnert hat, eine andere neue Funktion ( Ä) zu verwenden und :anstelle dessen, was ich ursprünglich hatte, zu verwenden.

ŻÄ׳:SI

Probieren Sie es online!

Jelly , 11 Bytes

0;+\÷S×ȷ2ḞI

Probieren Sie es online!

Erledigt neben caird coinheringaahing und user202729 im Chat .

Wie es funktioniert

0; + \ ÷ S × ȷ2ȷI - Volles Programm.

0; - Stellen Sie eine 0 voran.
  + \ - kumulative Summe.
    ÷ S - Geteilt durch die Summe der Eingaben.
      × ȷ2 - Mal 100. Ersetzt durch × ³ in der Monadic Link-Version.
         ḞI - Floor each, berechne die Inkremente (Deltas, Differenzen).
Mr. Xcoder
quelle
3

Haskell, 63 56 55 Bytes

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

Perl, 42 Bytes

Basierend auf Dennis 'Algorithmus

Beinhaltet +1 für -p

Führen Sie mit der Liste der Nummern auf STDIN, z

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

percent.pl:

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

Oktave, 40 Bytes

@(x)diff(ceil([0,cumsum(100*x/sum(x))]))
Alephalpha
quelle
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]
TessellatingHeckler
quelle
2

Brain-Flak , 150 Bytes

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

Probieren Sie es online!

Ausgehend vom Ende und rückwärts stellt dieser Code bei jedem Schritt sicher, dass die Summe der bisher ausgegebenen Zahlen dem gesamten Prozentsatz entspricht, der angetroffen wird, abgerundet.

(

  # 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
<>{}{}
Nitrodon
quelle
2

JavaScript (ES6) 60 63 95

Angepasst und vereinfacht von meiner (falschen) Antwort auf eine andere Herausforderung
Thk an @ l4m2, um festzustellen, dass dies auch falsch war

Behoben: Speichern von 1 Byte (und 2 Byte weniger, ohne den Namen zu zählen F=)

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

Testen Sie das folgende Snippet in einem beliebigen EcmaScript 6-kompatiblen Browser

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>

edc65
quelle
Nicht bestanden am[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
l4m2
@ l4m2 fehlgeschlagen, warum? Die Summe ist 100 undany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65
Der letzte sollte um 98 höchstens einen
Fehler haben
@ l4m2 uh, richtig, danke. Zeit zum Nachdenken
edc65
@ l4m2 sollte jetzt behoben sein
edc65
1

Rust, 85 Bytes

Dies verwendet Vektoren anstelle von Arrays, da es meines Wissens keine Möglichkeit gibt, Arrays mit mehreren unterschiedlichen Längen zu akzeptieren.

let a=|c:Vec<_>|c.iter().map(|m|m*100/c.iter().fold(0,|a,x|a+x)).collect::<Vec<_>>();
jus1in
quelle
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>

l4m2
quelle
0

Jq 1,5 , 46 Bytes

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

Erweitert

  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

Probieren Sie es online!

jq170727
quelle
0

PHP, 82 Bytes

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

Nimmt Eingaben von Befehlszeilenargumenten entgegen und druckt durch Unterstrich begrenzte Prozentsätze.

Laufen Sie mit -nroder versuchen Sie es online .

Titus
quelle
Diese gibt 15_15_15_15_15_25bei der Eingabe aus [2,2,2,2,3], was nicht richtig ist, weil3/13 ~= 23.1%
Sophia Lechner
@SophiaLechner Welche der Antworten macht das richtig?
Titus
Die meisten tun es tatsächlich. Die richtigen Antworten scheinen sich bisher auf einen von zwei Algorithmen zu stützen. der erste rundet die Prozentsätze der kumulierten Summen ab und nimmt die Differenz auf; Die zweite berechnet die Geschosse der Prozentsätze und erhöht dann die einzelnen Prozentsätze, um die Gesamtsumme auf 100 zu bringen.
Sophia Lechner,
@SophiaLechner Ich wollte nicht, dass ich es mir nicht anschaue. aber ich mache es später. Danke fürs bemerken.
Titus