Integer Percentify

21

Napisz funkcję, która pobiera listę liczb całkowitych dodatnich i zwraca listę liczb całkowitych zbliżonych do procentu całkowitego dla odpowiedniej liczby całkowitej w tej samej pozycji.

Wszystkie liczby całkowite na liście zwrotów muszą się sumować dokładnie do 100. Możesz założyć, że suma liczb całkowitych przekazanych jest większa niż 0. To, jak chcesz zaokrąglać lub obcinać ułamki dziesiętne, zależy od Ciebie, o ile dowolna wynikowa liczba całkowita zwracana jest w procentach jest wyłączony o nie więcej niż 1 w dowolnym kierunku.

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]

To jest , więc wygrywa najkrótszy kod w bajtach!

DaveAlger
źródło
Czy nasz algorytm musi być deterministyczny? Czy musi zawsze kończyć się w ograniczonym czasie?
lirtosiast
Mieliśmy już podobny problem z zaokrąglaniem, ale bardziej ogólny
edc65 10.10.15
1
I sugerują, że dodasz kolejny przypadek testowy: p([2,2,2,2,2,3]). Ma wiele możliwych odpowiedzi prawnych, ale nie wszystkie 2można przypisać do tej samej wartości. Eliminuje to wiele zbyt prostych algorytmów, które działają na wszystkich poprzednich testach, ponieważ zaokrąglanie nie jest takie złe.
Sophia Lechner,
4
Może p([1000,1000]) -> [49,51]?
l4m2
1
@ l4m2 Wydaje się to błędne, ale oba wyniki są wyłączone o 1 i nie więcej, więc postępuje zgodnie ze specyfikacją
edc65

Odpowiedzi:

20

Dyalog APL, 21 19 16 bajtów

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

Powyżej jest odpowiednikiem pociągu

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

Wypróbuj online.

Jak to działa

                 ⍝ 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
źródło
9
Gdyby tylko Fermat mógł wziąć od ciebie lekcje golfa.
TessellatingHeckler
1
@TessellatingHeckler Widzę, co tam zrobiłeś. Może wtedy będzie miał dość miejsca na marginesie na dowód. :)
mbomb007,
14

TI-BASIC, 26 23 16 bajtów

Do kalkulatorów serii TI-83 + / 84 +.

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

Dzięki @Dennis za piękny algorytm! Skumulowaną sumę listy bierzemy po przeliczeniu na procenty, a następnie na podłogę, zaznaczamy 0 z przodu i przyjmujemy różnice. ᴇ2jest o jeden bajt krótszy niż 100.

Przy tej samej liczbie bajtów jest:

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

Ciekawostka: %to dwubajtowy token, który mnoży liczbę przez 0,01 - ale nie ma sposobu, aby wpisać ją do kalkulatora! Musisz albo edytować źródło na zewnątrz, albo użyć programu asemblera.

Stary kod:

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

Pierwszy wiersz oblicza wszystkie zmienne procentowe, następnie drugi wiersz dodaje 1 do pierwszych Nelementów, gdzie Njest pozostały procent. cumSum(oznacza „sumę skumulowaną”.

Przykład z {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}

Nie będziemy tego robić N>dim([list], ponieważ żaden procent nie zmniejsza się o więcej niż 1 w podłogach.

lirtosiast
źródło
Nie jestem pewien, jak
liczycie
@DavidArenburg To tylko czytelna dla człowieka forma. Wszystkie żetony ( int(, sum(, Ans, itp) zajmują tylko jeden bajt.
Dennis,
4
+1 To jeden z najbardziej imponujących golfów TI-BASIC, jaki widziałem na tej stronie.
PhiNotPi,
Thomas, ta odpowiedź jest oszałamiająca!
DaveAlger,
Czy na pewno nie ma sposobu, aby wprowadzić %symbol? Myślałbym, że można go znaleźć w katalogu symboli ... Powinienem też wyciągnąć mój TI-84 + Silver. Nie używałem tego od dłuższego czasu. Block Dude jest niesamowity.
mbomb007,
7

CJam, 25 23 22 bajtów

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

Dzięki @ Sp3000 za 25 → 24.

Wypróbuj online.

Jak to działa

_                   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
źródło
5

Mathematica, 41 bajtów

(s=Floor[100#/Tr@#];s[[;;100-Tr@s]]++;s)&
alephalpha
źródło
Czekaj, co się tutaj dzieje?
patrz
@Seeq Algorytm jest jak stary kod w odpowiedzi TI-BASIC. Oblicza wszystkie zmienne procentowe, a następnie dodaje 1 do pierwszych Nelementów, gdzie Njest pozostały procent.
alephalpha
5

J (8,04 beta) , 59 bajtów (30 skradzionych bajtów)

30-bajtowy dosłowny port J odpowiedzi Dennisa na APL :

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

    f 1 1 2 4
12 13 25 50

59 bajtów odpowiedzi, najlepiej jak mogłem zrobić:

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

(Na podstawie reszty, która musi przejść do najwyższych wartości, nie więcej niż +1 każda, podzielona na wiele wartości w przypadku reszty> 1 lub remisu dla najwyższej wartości).

na przykład

   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

Wyjaśnienie

  • f=.3 : 0 - „f” jest zmienną, która jest typem czasownika (3), zdefiniowanym poniżej (: 0):
  • p=. zmienna „p”, zbudowana z:
    • y to lista liczb 1 0 2
    • +/y to „+” wstawiane pomiędzy każdą wartość ”/”, suma listy 3
    • y % (+/y) to oryginalne wartości y podzielone przez sumę: 0.333333 0 0.666667
    • 100 * (y%+/y)jest 100x tych wartości: 33.33.. 0 0.66...aby uzyskać wartości procentowe.
    • <. (100*y%+/y) to operator podłogi zastosowany do wartości procentowych: 33 0 66
  • r=. zmienna „r”, zbudowana z:
    • +/p jest sumą liczb zmiennoprzecinkowych: 99
    • 100 - (+/p) wynosi 100 - suma lub pozostałe punkty procentowe potrzebne do sumowania wartości procentowych do 100.
  • wynik, nie przechowywany:
    • r $ 1 jest listą 1, o ile liczba elementów, które musimy zwiększyć: 1 [1 1 ..]
    • #p jest długością listy procentowej
    • (#p - r) to liczba elementów, które nie zostaną zwiększone
    • (#p-r) $ 0 jest listą zer, o ile się to liczy: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) jest lista 1s, po której następuje lista 0: 1 0 0
    • \: pto lista indeksów, z których należy pobrać, paby uporządkować je w kolejności malejącej.
    • /: (\:p)to lista indeksów, z których należy wziąć \:pporządek w porządku rosnącym
    • ((r$1),(#p-r)$0)/:\:pbierze elementy z 1 1 0 0 .. .. Lista maska i sortowania więc istnieje 1s w pozycjach największych procentowe, po jednym dla każdej liczby musimy przyrostu i 0s do innych numerów: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p to wartości procentowe + maska, aby utworzyć listę wyników, która sumuje się do 100%, która jest wartością zwracaną przez funkcję.

na przykład

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

i

  • ) koniec definicji.

Nie mam dużego doświadczenia z J; Nie zdziwiłbym się, gdyby była wbudowana „lista zwrotów na procenty całkowitej” operacji i czystszy sposób na „zwiększenie n największych wartości”. (To 11 bajtów mniej niż moja pierwsza próba).

TessellatingHeckler
źródło
1
Bardzo fajny. Mam rozwiązanie python, ale jest znacznie dłuższe niż to. Dobra robota!
DaveAlger,
1
Jeśli nie zauważyłeś, zasady się zmieniły, więc powinieneś być w stanie znacznie je skrócić.
lirtosiast
@DaveAlger dzięki! @ThomasKwa Zauważyłem, nie jestem pewien, czy to mi znacznie pomaga - pierwsza próba mogę uzyskać -2 znaki. Musiałbym zmienić list[0:100-n] + list[:-100-n]podejście - i nie pomyślałem o innym sposobie podejścia.
TessellatingHeckler
4

JavaScript (ES6), 81 bajtów

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

Ten warunek „musi być równy 100” (zamiast zaokrąglać i sumować) prawie podwoił mój kod (z 44 do 81). Sztuczka polegała na dodaniu puli dla wartości dziesiętnych, która, gdy osiągnie 1, bierze 1 od siebie i dodaje ją do bieżącej liczby. Problemem były wtedy zmiennoprzecinkowe, co oznacza, że ​​coś w rodzaju [1,1,1] pozostawia resztę 0,9999999999999858. Więc zmieniłem czek na większy niż .999 i postanowiłem nazwać to wystarczająco precyzyjnie.

Mwr247
źródło
4

Haskell, 42 27 bajtów

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

Praktycznie prosta metoda w Haskell, z kilkoma miejscami do gry w golfa.

Konsola (w nawiasie podano spójność z przykładem):

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

Edycja: ćwiczyłem moje stawianie, dokonałem oczywistych zamian.

Oryginalny:

p xs=[div(x*100)tot|x<-xs]where tot=sum xs
Jake
źródło
1
Suma listy powinna wynosić 100. W twoim pierwszym przykładzie jest to 99
Damien
4

Galareta , 7 bajtów

-2 dzięki Dennisowi, przypominając mi o użyciu innej nowej funkcji ( Ä) i używania :zamiast tego, co początkowo miałem.

ŻÄ׳:SI

Wypróbuj online!

Galaretka , 11 bajtów

0;+\÷S×ȷ2ḞI

Wypróbuj online!

Sporządzono wraz z Cairnem coinheringaahing i użytkownikiem202729 na czacie .

Jak to działa

0; + \ ÷ S × ȷ2ḞI - Pełny program.

0; - Przygotuj 0.
  + \ - Skumulowana suma.
    ÷ S - Dzielony przez sumę danych wejściowych.
      × ȷ2 - Razy 100. Zastąpiony przez × ³ w monadycznej wersji łącza.
         ḞI - Piętro każdy, oblicz przyrosty (delty, różnice).
Pan Xcoder
źródło
3

Haskell, 63 56 55 bajtów

p l=tail>>=zipWith(-)$[100*x`div`sum l|x<-0:scanl1(+)l]
Damien
źródło
3

Perl, 42 bajty

Na podstawie algorytmu Dennisa

Obejmuje +1 dla -p

Uruchom z listą numerów na STDIN, np

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

percent.pl:

s%\d+%-$-+($-=$a+=$&*100/eval y/ /+/r)%eg
Ton Hospel
źródło
2

Oktawa, 40 bajtów

@(x)diff(ceil([0,cumsum(100*x/sum(x))]))
alephalpha
źródło
2

Python 2, 89 bajtów

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
źródło
2

Brain-Flak , 150 bajtów

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

Wypróbuj online!

Począwszy od końca i pracując wstecz, ten kod zapewnia na każdym etapie, że suma dotychczasowych liczb wyjściowych jest równa całkowitej napotkanej wartości procentowej, zaokrąglonej w dół.

(

  # 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
źródło
2

JavaScript (ES6) 60 63 95

Dostosowane i uproszczone na podstawie mojej (złej) odpowiedzi na inne wyzwanie
Dziękujemy za @ l4m2 za odkrycie, że to też było złe

Naprawiono zapisywanie 1 bajtu (i 2 bajtów mniej, nie licząc nazwy F=)

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

Przetestuj poniższy fragment kodu w dowolnej przeglądarce zgodnej z 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>

edc65
źródło
Nie powiodło się[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
l4m2
@ l4m2 nie powiodło się dlaczego? Suma wynosi 100 iany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65
Ten ostatni powinien być co najwyżej jeden na 98, ale jest 100
l4m2
@ l4m2 uh, racja, dzięki. Czas pomyśleć jeszcze raz
edc65
@ l4m2 powinien zostać teraz naprawiony
edc65
1

Rdza, 85 bajtów

Używa to wektorów zamiast tablic, ponieważ o ile mi wiadomo, nie ma możliwości zaakceptowania tablic o wielu różnych długościach.

let a=|c:Vec<_>|c.iter().map(|m|m*100/c.iter().fold(0,|a,x|a+x)).collect::<Vec<_>>();
jus1in
źródło
1

JavaScript, 48 bajtów

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
źródło
0

Jq 1,5 , 46 bajtów

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

Rozszerzony

  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

Wypróbuj online!

jq170727
źródło
0

PHP, 82 bajty

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

pobiera dane z argumentów wiersza poleceń, drukuje wartości procentowe rozdzielone znakiem podkreślenia.

Uruchom -nrlub wypróbuj online .

Tytus
źródło
To wychodzi, 15_15_15_15_15_25gdy podano dane wejściowe [2,2,2,2,3], co jest nie tak, ponieważ3/13 ~= 23.1%
Sophia Lechner
@SophiaLechner Która z odpowiedzi działa poprawnie?
Tytus
Właściwie większość tak. Jak dotąd poprawne odpowiedzi wydają się być oparte na jednym z dwóch algorytmów; pierwszy zaokrągla procent łącznych sum i bierze różnicę; drugi oblicza dolne wartości procentowe, a następnie zwiększa wystarczająco wyraźne wartości procentowe, aby suma wyniosła 100.
Sophia Lechner
@SophiaLechner Nie miałem na myśli, że nie zajrzę w to; ale zrobię to później. Dzięki za zauważenie.
Tytus