Persen Bilangan Bulat

21

Tulis fungsi yang mengambil daftar bilangan bulat positif dan mengembalikan daftar bilangan bulat yang mendekati persentase total untuk bilangan bulat yang sesuai di posisi yang sama.

Semua bilangan bulat dalam daftar kembali harus benar-benar menambahkan hingga 100. Anda dapat mengasumsikan jumlah bilangan bulat yang dilewatkan lebih besar dari 0. Bagaimana Anda ingin membulatkan atau memotong desimal terserah Anda selama setiap bilangan bulat tunggal yang dihasilkan dikembalikan sebagai persentase dimatikan oleh tidak lebih dari 1 di kedua arah.

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]

Ini adalah , jadi kode terpendek dalam byte menang!

DaveAlger
sumber
Haruskah algoritma kami bersifat deterministik? Haruskah itu selalu berakhir dalam waktu yang terbatas?
lirtosiast
Kami sudah memiliki beberapa masalah pembulatan yang serupa tetapi lebih umum
edc65
1
Saya menyarankan agar Anda menambahkan kasus uji lain: p([2,2,2,2,2,3]). Ini memiliki banyak kemungkinan jawaban hukum, tetapi tidak semua 2dapat dipetakan dengan nilai yang sama. Ini menghilangkan banyak algoritma yang terlalu sederhana yang bekerja pada semua kasus pengujian sebelumnya karena pembulatan tidak terlalu buruk.
Sophia Lechner
4
Bisakah p([1000,1000]) -> [49,51]?
14m2
1
@ l4m2 Tampaknya salah, tetapi kedua hasil dimatikan oleh 1 dan tidak lebih, sehingga mengikuti spesifikasi
edc65

Jawaban:

20

Dyalog APL, 21 19 16 byte

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

Di atas adalah setara kereta

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

Cobalah online.

Bagaimana itu bekerja

                 ⍝ 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
sumber
9
Andai saja Fermat bisa mengambil pelajaran golf dari Anda.
TessellatingHeckler
1
@ TessellatingHeckler Saya melihat apa yang Anda lakukan di sana. Mungkin kemudian dia punya cukup ruang di margin untuk pembuktiannya. :)
mbomb007
14

TI-BASIC, 26 23 16 byte

Untuk kalkulator TI-83 + / 84 + series.

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

Terima kasih kepada @Dennis untuk algoritme yang indah! Kami mengambil jumlah kumulatif daftar setelah mengonversi ke persen, lalu naik, menempelkan 0 ke depan, dan mengambil perbedaan. ᴇ2lebih pendek satu byte dari 100.

Pada hitungan byte yang sama adalah:

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

Fakta menyenangkan: %adalah token dua byte yang mengalikan angka dengan 0,01 — tetapi tidak ada cara untuk memasukkannya ke dalam kalkulator! Anda perlu mengedit sumber di luar atau menggunakan program perakitan.

Kode lama:

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

Baris pertama menghitung semua persen lantai, lalu baris kedua menambahkan 1 ke Nelemen pertama , di mana Npersentase tersisa. cumSum(singkatan dari "jumlah kumulatif".

Contoh dengan {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}

Kami tidak akan memilikinya N>dim([list], karena tidak ada persentase yang berkurang lebih dari 1 di lantai.

lirtosiast
sumber
Tidak yakin bagaimana Anda menghitung byte di sini, sepertinya jauh lebih lama daripada saya
David Arenburg
@ Davidviden Ini hanya bentuk yang bisa dibaca manusia. Semua token ( int(, sum(, Ans, dll) menempati hanya satu byte.
Dennis
4
+1 Ini adalah salah satu golf TI-BASIC paling mengesankan yang pernah saya lihat di situs ini.
PhiNotPi
Thomas jawaban ini luar biasa!
DaveAlger
Apakah Anda yakin tidak ada cara untuk memasukkan %simbol? Saya akan berpikir itu bisa ditemukan di katalog simbol ... Juga, saya harus mengeluarkan TI-84 + Perak. Saya belum menggunakannya dalam beberapa saat. Block Dude luar biasa.
mbomb007
7

CJam, 25 23 22 byte

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

Terima kasih kepada @ Sp3000 untuk 25 → 24.

Cobalah online.

Bagaimana itu bekerja

_                   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
sumber
5

Mathematica, 41 byte

(s=Floor[100#/Tr@#];s[[;;100-Tr@s]]++;s)&
alephalpha
sumber
Tunggu, apa yang terjadi di sini?
seequ
@Seeq Algoritma itu seperti kode lama dalam jawaban TI-BASIC. Ini menghitung semua persen lantai, lalu menambahkan 1 ke Nelemen pertama , di mana Npersentase yang tersisa.
alephalpha
5

J (8,04 beta) , 59 byte (30 dicuri byte)

30 byte literal J-port jawaban Dennis's APL :

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

    f 1 1 2 4
12 13 25 50

59 byte jawaban, yang terbaik yang bisa saya lakukan sendiri:

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

(Berdasarkan sisanya harus pergi ke nilai tertinggi, masing-masing tidak lebih dari +1, dibagi beberapa nilai dalam kasus sisa> 1 atau dasi untuk nilai tertinggi).

misalnya

   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

Penjelasan

  • f=.3 : 0 - 'f' adalah variabel, yang merupakan jenis kata kerja (3), didefinisikan di bawah (: 0):
  • p=. variabel 'p', dibangun dari:
    • y adalah daftar angka 1 0 2
    • +/y adalah '+' diletakkan di antara setiap nilai '/', jumlah daftar 3
    • y % (+/y) adalah nilai y asli dibagi dengan jumlah: 0.333333 0 0.666667
    • 100 * (y%+/y)adalah 100x nilai-nilai itu: 33.33.. 0 0.66...untuk mendapatkan persentase.
    • <. (100*y%+/y) adalah operator lantai diterapkan ke persentase: 33 0 66
  • r=. variabel 'r', dibangun dari:
    • +/p adalah jumlah dari persentase lantai: 99
    • 100 - (+/p) adalah 100 - jumlah, atau sisa poin persentase yang diperlukan untuk membuat persentase jumlah menjadi 100.
  • hasil, tidak disimpan:
    • r $ 1 adalah daftar 1s, asalkan jumlah item yang perlu kita tambahkan: 1 [1 1 ..]
    • #p adalah panjang daftar persentase
    • (#p - r) adalah jumlah item yang tidak akan bertambah
    • (#p-r) $ 0 adalah daftar 0s selama yang dihitung: 0 0 [0 ..]
    • ((r$1) , (#p-r)$0) adalah daftar 1s diikuti oleh daftar 0s: 1 0 0
    • \: padalah daftar indeks yang harus diambil puntuk meletakkannya dalam urutan menurun.
    • /: (\:p)adalah daftar indeks yang harus diambil \:puntuk menempatkannya dalam urutan menaik
    • ((r$1),(#p-r)$0)/:\:padalah mengambil unsur-unsur dari 1 1 .. 0 0 .. daftar masker dan menyortir jadi ada 1s dalam posisi persentase terbesar, satu untuk setiap nomor kita perlu peningkatan, dan 0s untuk nomor lain: 0 0 1.
    • p + ((r$1),(#p-r)$0)/:\:p adalah persentase + topeng, untuk membuat daftar hasil yang berjumlah 100%, yang merupakan nilai pengembalian fungsi.

misalnya

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

dan

  • ) akhir definisi.

Saya tidak terlalu berpengalaman dengan J; Saya tidak akan terlalu terkejut jika ada "mengubah daftar menjadi persentase dari total" operasi yang dibangun, dan cara yang lebih bersih untuk "meningkatkan n nilai terbesar" juga. (Ini 11 byte kurang dari upaya pertama saya).

TessellatingHeckler
sumber
1
Sangat keren. Saya punya solusi python tetapi jauh lebih lama dari ini. Kerja bagus!
DaveAlger
1
Jika Anda belum menyadarinya, aturannya telah berubah, jadi Anda harus dapat mempersingkat ini.
lirtosiast
@DaveAlger terima kasih! @ThomasKwa saya perhatikan, saya tidak yakin itu sangat membantu saya - usaha pertama saya bisa mendapatkan -2 karakter. Saya perlu mengubah list[0:100-n] + list[:-100-n]pendekatan - dan saya belum memikirkan cara lain untuk mendekatinya.
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)))

Kondisi "harus sama dengan 100" (bukan pembulatan dan penjumlahan) hampir dua kali lipat kode saya (44-81). Triknya adalah menambahkan pot untuk nilai desimal yang, setelah mencapai 1, mengambil 1 dari dirinya sendiri dan menambahkannya ke angka saat ini. Masalahnya adalah floating point, yang berarti sekitar [1,1,1] menyisakan 0,9999999999999858. Jadi saya mengubah cek menjadi lebih dari 0,999, dan memutuskan untuk menyebutnya cukup tepat.

Mwr247
sumber
4

Haskell, 42 27 byte

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

Cukup banyak metode sepele di Haskell, dengan beberapa ruang dihapus untuk bermain golf.

Konsol (tanda kurung dimasukkan agar konsisten dengan contoh):

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

Sunting: melatih puting saya, membuat beberapa penggantian yang jelas.

Asli:

p xs=[div(x*100)tot|x<-xs]where tot=sum xs
Jake
sumber
1
Jumlah dari daftar harus 100. Dalam contoh pertama Anda, itu adalah 99
Damien
4

Jelly , 7 byte

-2 Terima kasih kepada Dennis, mengingatkan saya untuk menggunakan fitur baru lain ( Ä) dan menggunakan :bukan apa yang awalnya saya miliki.

ŻÄ׳:SI

Cobalah online!

Jelly , 11 byte

0;+\÷S×ȷ2ḞI

Cobalah online!

Dilakukan bersama caird coinheringaahing dan user202729 dalam obrolan .

Bagaimana itu bekerja

0; + \ ÷ S × ȷ2ḞI - Program lengkap.

0; - Sertakan 0.
  + \ - Jumlah kumulatif.
    ÷ S - Dibagi dengan jumlah input.
      × ȷ2 - Kali 100. Digantikan oleh × ³ dalam versi tautan monadik.
         ḞI - Lantai masing-masing, menghitung kenaikan (delta, perbedaan).
Tuan Xcoder
sumber
3

Haskell, 63 56 55 byte

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

Perl, 42 byte

Berdasarkan algoritma Dennis

Termasuk +1 untuk -p

Jalankan dengan daftar angka pada STDIN, mis

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

percent.pl:

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

Oktaf, 40 byte

@(x)diff(ceil([0,cumsum(100*x/sum(x))]))
alephalpha
sumber
2

Python 2, 89 byte

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
sumber
2

Brain-Flak , 150 byte

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

Cobalah online!

Mulai dari akhir dan bekerja mundur, kode ini memastikan pada setiap langkah bahwa jumlah nomor output sejauh ini sama dengan persentase total yang ditemui, dibulatkan ke bawah.

(

  # 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
sumber
2

JavaScript (ES6) 60 63 95

Diadaptasi dan disederhanakan dari jawaban saya (salah) untuk tantangan lain. Terima kasih
kepada @ l4m2 untuk mengetahui bahwa ini juga salah

Memperbaiki penghematan 1 byte (dan 2 byte lebih sedikit, tidak termasuk nama F=)

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

Tes menjalankan cuplikan di bawah ini di peramban apa pun yang mendukung 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
sumber
Gagal[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
14m2
@ l4m2 gagal kenapa? Jumlahnya 100 danany single resulting integer returned as a percentage is off by no more than 1 in either direction.
edc65
Yang terakhir harus paling banyak satu kali pada 98, tetapi 100
l4m2
@ l4m2 uh, benar, terima kasih. Waktu untuk berpikir lagi
edc65
@ l4m2 harus diperbaiki sekarang
edc65
1

Karat, 85 byte

Ini menggunakan vektor bukan array karena sejauh yang saya tahu tidak ada cara untuk menerima array dengan panjang yang berbeda.

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

JavaScript, 48 byte

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
sumber
0

Jq 1,5 , 46 byte

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

Diperluas

  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

Cobalah online!

jq170727
sumber
0

PHP, 82 byte

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

mengambil input dari argumen baris perintah, mencetak persentase yang dibatasi oleh garis bawah.

Jalankan dengan -nratau coba online .

Titus
sumber
Output ini 15_15_15_15_15_25ketika diberi input [2,2,2,2,3], yang tidak benar karena3/13 ~= 23.1%
Sophia Lechner
@SophiaLechner Jawaban mana yang benar?
Titus
Kebanyakan melakukannya. Jawaban yang benar sejauh ini tampaknya dibangun di sekitar salah satu dari dua algoritma; putaran pertama menghilangkan persentase jumlah kumulatif dan mengambil perbedaan; yang kedua menghitung tingkat persentase dan kemudian meningkatkan persentase yang cukup berbeda sehingga total menjadi 100.
Sophia Lechner
@SophiaLechner Saya tidak bermaksud tidak akan memeriksanya; tapi saya akan lakukan nanti. Terima kasih telah memperhatikan.
Titus