Цілий показник


21

Напишіть функцію, яка займає список додатних цілих чисел і повертає список цілих чисел, приблизних відсоткам від загального числа для відповідного цілого числа в тій же позиції.

Усі цілі числа у списку повернень повинні точно додати до 100. Ви можете вважати, що сума цілих чисел, переданих у цілому, перевищує 0. Як вирішити округлення або скорочення десяткових знаків, залежить від вас, доки будь-яке єдине ціле число повернене у відсотках відключається не більше ніж на 1 в будь-якому напрямку.

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]

Це , тому найкоротший код у байтах виграє!


Чи повинен наш алгоритм бути детермінованим? Повинно це завжди припинятися протягом обмеженого часу?
lirtosiast

У нас вже була якась проблема округлення, схожа, але більш загальна
edc65

1
Я пропоную вам додати ще один тестовий приклад: p([2,2,2,2,2,3]). Він має багато можливих юридичних відповідей, але не всі 2з них можна зіставити на одне значення. Це виключає безліч надто простих алгоритмів, які працюють у всіх попередніх тестових випадках, оскільки округлення не надто погане.
Софія Лехнер

4
Можна p([1000,1000]) -> [49,51]?
l4m2

1
@ L4m2 Це здається неправильним, але обидва результати вимкнені на 1 і не більше, тому слід специфікація
edc65

Відповіді:


20

Діялог APL, 21 19 16 байт

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

Наведене вище - еквівалент поїздів

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

Спробуйте в Інтернеті.

Як це працює

                 ⍝ 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
Якби тільки Фермат міг взяти у вас уроки з гольфу.
TessellatingHeckler

1
@TessellatingHeckler Я бачу, що ти там робив. Можливо, тоді йому вистачить місця на полях для його доказування. :)
mbomb007

14

TI-BASIC, 26 23 16 байт

Для калькуляторів серії TI-83 + / 84 +.

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

Дякуємо @Dennis за прекрасний алгоритм! Ми беремо сукупну суму списку після перерахунку на відсотки, потім підлогу, ставимо 0 на передню частину та приймаємо різниці. ᴇ2на один байт коротший за 100.

При цьому кількість байтів:

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

Забавний факт: %це двобайтовий маркер, який помножує число на .01 - але немає способу ввести його в калькулятор! Вам потрібно або відредагувати джерело зовні, або скористатися програмою складання.

Старий код:

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

Перший рядок обчислює всі залишки на площі, потім другий рядок додає 1 до перших Nелементів, де Nзалишився відсоток. cumSum(означає "сукупна сума".

Приклад із {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>dim([list], тому що жоден відсоток не зменшується більш ніж на 1 в підлозі.


Не впевнений, як ви тут підраховуєте байти, мені здається жахливо довше, ніж 23
Девід Аренбург

@DavidArenburg Це просто читабельна для людини форма. Всі жетони ( int(, sum(, Ansі т.д.) займають лише один байт.
Денніс

4
+1 Це одне з найбільш вражаючих гольфів TI-BASIC, які я бачив на цьому сайті.
PhiNotPi

Томас ця відповідь приголомшливий!
DaveAlger

Ви впевнені, що немає ніякого способу ввести %символ? Я б подумав, що його можна знайти в каталозі символів ... Крім того, я повинен отримати свій TI-84 + Silver. Я не використовував його деякий час. Блок Чувак - приголомшливий.
mbomb007

7

CJam, 25 23 22 байт

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

Завдяки @ Sp3000 за 25 → 24.

Спробуйте в Інтернеті.

Як це працює

_                   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

Математика, 41 байт

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

Зачекайте, що тут відбувається?
seequ

@Seeq Алгоритм схожий на старий код у відповіді TI-BASIC. Він обчислює всі площі, що додаються, а потім додає 1 до перших Nелементів, де Nзалишився відсоток.
алефальфа

5

J (8,04 бета) , 59 байт (30 вкрадених байт)

30-байтний буквальний J-порт відповіді Денніса на APL :

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

    f 1 1 2 4
12 13 25 50

59 байт відповідають, найкраще, що я міг зробити сам:

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

(Виходячи з залишку, який повинен переходити до найвищих значень, не більше +1 кожне, розділити на декілька значень у випадку залишку> 1 або крапки з найвищим значенням).

напр

   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

Пояснення

  • f=.3 : 0 - 'f' - це змінна, що є типом дієслова (3), визначеним нижче (: 0):
  • p=. змінна 'p', побудована з:
    • y - це список номерів 1 0 2
    • +/y є "+", розміщене між кожним значенням "/", сума списку 3
    • y % (+/y) є вихідними значеннями y, розділеними на суму: 0.333333 0 0.666667
    • 100 * (y%+/y)є 100x ці значення: 33.33.. 0 0.66...отримати відсотки.
    • <. (100*y%+/y) - оператор підлоги, застосований до відсотків: 33 0 66
  • r=. змінна 'r', побудована з:
    • +/p - це сума заквашених відсотків: 99
    • 100 - (+/p) є 100 - сума, або решта відсоткових балів, необхідних для того, щоб відсоткові суми становили 100.
  • результат, не зберігається:
    • r $ 1 - це список з 1-го розміру, якщо кількість елементів, які нам потрібно збільшити: 1 [1 1 ..]
    • #p - довжина списку відсотків
    • (#p - r) - це кількість елементів, які не збільшуватимуться
    • (#p-r) $ 0 - це список 0, якщо це число: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) - це список 1, який супроводжується списком 0: 1 0 0
    • \: p- це список індексів, з яких потрібно взяти, pщоб привести їх у порядку зменшення.
    • /: (\:p)- це список індексів, з яких слід взяти \:pце у порядку зростання
    • ((r$1),(#p-r)$0)/:\:pприймають елементи з 1 + 1 .. 0 0 .. список маски і сортування так є 1s в позиціях найбільших відсотків, по одному для кожного номера , ми повинні збільшенню і 0s для інших чисел: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p це відсотки + маска, щоб скласти список результатів, який становить 100%, що є значенням повернення функції.

напр

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

і

  • ) кінець визначення.

Я не дуже досвідчений з J; Я би не надто здивувався, якщо вбудований "перелік поворотів у відсотках від загальної кількості", і більш чіткий спосіб "збільшити n найбільших значень". (Це на 11 байт менше, ніж моя перша спроба).


1
Дуже круто. У мене є рішення пітона, але воно набагато довше, ніж це. Хороша робота!
DaveAlger

1
Якщо ви цього не помітили, правила змінилися, тому вам слід мати можливість скоротити це.
lirtosiast

@DaveAlger дякую! @ThomasKwa Я помітив, я не впевнений, що це мені значно допомагає - з першої спроби я можу отримати -2 символи. Мені потрібно було б змінити list[0:100-n] + list[:-100-n]підхід - і я не думав про інший спосіб наблизитися до нього.
TessellatingHeckler

4

JavaScript (ES6), 81 байт

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

Ця умова "повинна дорівнювати 100" (а не округлення та додавання) майже подвоїла мій код (з 44 до 81). Хитрість полягала в тому, щоб додати горщик для десяткових значень, який, як тільки він досягне 1, бере 1 від себе і додає його до поточного числа. Тоді проблемою були плаваючі точки, що означає, що щось на зразок [1,1,1] залишає залишок .9999999999999858. Тому я змінив чек на більший, ніж на 999, і вирішив назвати це досить точно.


4

Haskell, 42 27 байт

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

Досить тривіальний метод в Хаскеллі, з кількох просторів, видалених для гольфу.

Консоль (включені дужки, щоб відповідати прикладу):

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

Редагувати: практикував моє ставлення, робив явні заміни.

Оригінал:

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

1
Сума списку повинна бути 100. У вашому першому прикладі це 99
Демієн

4

Желе , 7 байт

-2 завдяки Деннісу, який нагадував мені використовувати ще одну нову функцію ( Ä) та використовувати :замість того, що я мав спочатку.

ŻÄ׳:SI

Спробуйте в Інтернеті!

Желе , 11 байт

0;+\÷S×ȷ2ḞI

Спробуйте в Інтернеті!

У чаті поруч із спільнотою coirdheraahing і користувачем202729 .

Як це працює

0; + \ ÷ S × ȷ2ḞI - Повна програма.

0; - Додайте 0.
  + \ - Сукупна сума.
    ÷ S - Ділиться на суму введеного.
      × ȷ2 - Times 100. Замінено на × ³ у версії монадичного посилання.
         ḞI - Поверх кожного, обчислюємо прирости (дельти, різниці).


3

Perl, 42 байти

На основі алгоритму Денніса

Включає +1 для -p

Виконати зі списком чисел на STDIN, наприклад

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

percent.pl:

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


2

Python 2, 89 байт

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

Мозок-Флак , 150 байт

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

Спробуйте в Інтернеті!

Починаючи з кінця і працюючи назад, цей код забезпечує на кожному кроці, що сума вихідних чисел досі дорівнює загальному відсотку, що виникає, округлюється вниз.

(

  # 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

Адаптований та спрощений з моєї (неправильної) відповіді на інший виклик "
Тьк до" l4m2 для виявлення того, що це теж було неправильно

Виправлено збереження на 1 байт (і на 2 байти менше, не рахуючи імені F=)

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

Перевірте запуск фрагмента нижче в будь-якому веб-переглядачі, сумісному з 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>


Помилка[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
l4m2

@ l4m2 не вдалося чому? Сума становить 100 іany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65

Останній повинен бути максимум один раз на 98, але це 100
м2

@ l4m2 uh, правильно, спасибі. Час ще раз подумати
edc65,

@ l4m2 слід виправити зараз
edc65

1

Іржа, 85 байт

Для цього використовуються вектори замість масивів, оскільки, наскільки я знаю, немає способу прийняти масиви з різною довжиною.

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

1

JavaScript, 48 байт

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 байт

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

Розширено

  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

Спробуйте в Інтернеті!


0

PHP, 82 байти

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

приймає дані з аргументів командного рядка, друкує відсотки, розмежовані підкресленням.

Запустіть -nrабо спробуйте в Інтернеті .


Це виводиться, 15_15_15_15_15_25коли дається вхід [2,2,2,2,3], що не вірно, тому що3/13 ~= 23.1%
Софія Лехнер

@SophiaLechner Яка з відповідей робить це правильно?
Тит

Більшість насправді. На сьогодні правильні відповіді, здається, побудовані навколо одного з двох алгоритмів; перший округляє відсотки сукупних сум і приймає різницю; другий обчислює поверхи відсотків, а потім приріст, достатньо чітких відсотків, щоб довести загальну суму до 100.
Софія Лехнер

@SophiaLechner Я не мав на увазі, що не хочу в це дивитись; але я зроблю пізніше Дякуємо, що помітили.
Тит
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.