整数百分比
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]
这是代码高尔夫球,因此以字节为单位的最短代码胜出!
我们的算法必须是确定性的吗?是否必须始终在限定时间内终止?
我们已经有一些类似但更通用的取整问题
1
我建议您添加另一个测试用例:p([2,2,2,2,2,3])。它有许多可能的法律答案,但并非所有2的都可以映射为相同的值。这样就消除了许多在所有先前的测试用例上都可以使用的过于简单的算法,因为四舍五入还算不错。
4
可以p([1000,1000]) -> [49,51]吗
1
@ l4m2这似乎是错误的,但是两个结果都相差1并且没有更多,因此遵循规范
Answers:
20
Dyalog 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
如果只有Fermat可以从您那里学习高尔夫球课程,
1
@TessellatingHeckler我明白你在那里做了什么。也许那时他在空白处有足够的空间供他取证。:)
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高尔夫球之一。
您确定无法输入%符号吗?我以为可以在符号目录中找到它。此外,我应该拿出TI-84 +银牌。我已经有一段时间没有使用它了。Block Dude很棒。
7
CJam,25 23 22字节
{_:e2\:+f/_:+100-Xb.+}
感谢@ Sp3000 for 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
Mathematica,41个字节
(s=Floor[100#/Tr@#];s[[;;100-Tr@s]]++;s)&
等等,这会发生什么?
@Seeq该算法类似于TI-BASIC答案中的旧代码。它计算所有下限百分比,然后将1添加到第一个N元素,这里N是剩余的百分比。
5
J(8.04 beta),59个字节(30个被盗字节)
f=.3 :'+/\^:_1<.100>
f 1 1 2 4
12 13 25 50
59个字节的答案,最好是我自己做:
f=.3 :0
p=.<.100>
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) 是这些值的100倍: 33.33.. 0 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) 是1s列表,然后是0s列表: 1 0 0
\: p 是要获取的索引列表 p要按降序排列。
/: (\:p)是要从\:p中升序排列的索引列表
((r$1),(#p-r)$0)/:\:p从1取的元素.. 0 0 ..面膜排行榜和分拣所以有1秒的最大百分比,每一个我们需要增加的编号的位置,和0为其他号码: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
很酷。我有一个python解决方案,但是比这个更长。干得好!
1
如果您没有注意到,规则已经更改,因此您应该可以大大缩短此时间。
@DaveAlger谢谢!我注意到@ThomasKwa,我不确定它是否对我有很大帮助-第一次尝试我可以得到-2个字符。我需要更改list[0:100-n] + list[:-100-n]方法-而且我还没有想到另一种方法。
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
Haskell中的微不足道的方法几乎没有,打高尔夫球的空间也有所减少。
控制台(随附的括号与示例保持一致):
*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
1
列表的总和应为100。在您的第一个示例中,列表为99
4
果冻,7个字节
-2感谢Dennis,提醒我使用另一个新功能(Ä),并使用:原来的功能。
ŻÄ׳:SI
果冻,11字节
0;+\÷S×ȷ2ḞI
怎么运行的
0; + \÷S×ȷ2ḞI-完整程序。
0; -加上0。
+ \-累计和。
÷S-除以输入总和。
×ȷ2-乘以100。在单声道链接版本中由׳代替。
-I-分别取下,计算增量(增量,差)。
3
Haskell,63 56 55字节
p l=tail>>=zipWith(-)$[100*x`div`sum l|x
3
Perl,42个字节
基于丹尼斯算法
包括+1的 -p
使用STDIN上的数字列表运行,例如
perl -p percent.pl <<< "1 0 2"
percent.pl:
s%\d+%-$-+($-=$a+=$&*100/eval y/ /+/r)%eg
2
八度,40字节
@(x)diff(ceil([0,cumsum(100*x/sum(x))]))
2
Python 2,89个字节
deff(L):p=[int(x/0.01/sum(L))forxinL]foriinrange(100-sum(p)):p[i]+=1returnpprintf([16,16,16,16,16,16])printf([1,0,2])->[17,17,17,17,16,16][34,0,66]
2
((([]){[{}]({}<>)<>([])}{})[()])<>([]){{}<>([{}()]({})<>(((((({})({})({})){}){}){}{}){}){}())<>{(({})){({}[()])<>}{}}{}([])}<>{}{}
从头开始并向后工作,此代码可确保在每个步骤中,到目前为止的输出数之和等于所遇到的总百分比,并四舍五入。
(
# 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的 Thk的因为发现这也是错误的
固定保存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]))
运行代码段Hide results
失败[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,980]
@ l4m2为何失败?总和为100any single resulting integer returned as a percentage is off by no more than 1 in either direction.
最后一个应该最多
@ l4m2恩,对,谢谢。该再想一想
@ l4m2应该现在被固定
1
Rust,85个字节
它使用向量而不是数组,因为据我所知,没有办法接受多个不同长度的数组。
let a=|c:Vec<_>|c.iter().map(|m|m*100/c.iter().fold(0,|a,x|a+x)).collect::>();
1
JavaScript,48个字节
F=x=>x.map(t=>s+=t,y=s=0).map(t=>-y+(y=100*t/s|0))// Testconsole.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]))
运行代码段Hide results
0
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
从命令行参数获取输入,输出下划线分隔的百分比。
运行-nr或在线尝试。
15_15_15_15_15_25当给出输入时[2,2,2,2,3],此输出是不正确的,因为3/13 ~= 23.1%
@SophiaLechner哪个答案正确?
实际上,大多数都这样做。到目前为止,正确答案似乎是围绕两种算法之一建立的;第一个四舍五入计算累加总和的百分比并取差额;第二个计算百分比的下限,然后增加足够的不同百分比以使总数达到100。
@SophiaLechner我不是说我不会调查它;但我以后再说。感谢您的关注。