以下是“Ruby”方式执行以下操作的方法;我仍然以更加命令式的编程风格思考,而没有真正适应以Ruby思考。我想要做的是找到大小最接近数组平均值的元素,例如,考虑以下数组。
[1,2,3]
平均值为2.0。我想编写的方法将从上下两个方向返回最接近平均值的元素,即1和3。
下面的另一个例子会更好地说明这一点:
[10,20,50,33,22] avg is 27.0 method would return 22 and 33.
这不是最有效的方法,但(在我谦虚的看法中)它非常符合Ruby编程风格。
class Array
# Return the single element in the array closest to the average value
def closest_to_average
avg = inject(0.0,:+) / length
min_by{ |v| (v-avg).abs }
end
end
[1,2,3].closest_to_average
#=> 2
[10,20,50,33,22].closest_to_average
#=> 22
如果您真的想要最接近的n个项目,则:
class Array
# Return a number of elements in the array closest to the average value
def closest_to_average(results=1)
avg = inject(0.0,:+) / length
sort_by{ |v| (v-avg).abs }[0,results]
end
end
[10,20,50,33,22].closest_to_average #=> [22]
[10,20,50,33,22].closest_to_average(2) #=> [22, 33]
[10,20,50,33,22].closest_to_average(3) #=> [22, 33, 20]
avg = inject(0.0,:+) / length
这是一种简写方式:
avg = self.inject(0.0){ |sum,n| sum+n } / self.length
我从一个值0.0
开始,而不是0
,以确保总和将是浮点数,这样除以长度不会给我一个整数舍入的值。
sort_by{ |v| (v-avg).abs }
根据数字与平均值之间的差异(从低到高)对数组进行排序,然后:
[0,results]
从该数组中选择前results个条目。
inject(:+)
就是一个更简洁的方式来获得数组中所有元素的总和。 - SparkyRobinsonnil
而不是0.0
(导致在进行除法时出错)。这种边缘情况是我使用该形式的唯一原因。感谢您指出这一点,加1。 - Phrogzinject
时,将:+转换为proc并非必要。我认为在讨论初始值时,这一点可能被忽略了。 - Cary Swovelandinject(0.0,:+)
;感谢你的推动,让我去检查并发现真相。这个Core方法有这种便利性确实让我感到不安,因为其他很多方法都没有。然而,它稍微更易读和方便,所以我已经编辑了回复来使用它(即使它只是Ruby语法中另一个记忆魔法的例子)。 - Phrogzinject
的初始值,这样如果没有浮点数,就可以使用整数算术进行求和,然后再除以 length.to_f
。能够向 inject
传递一个符号是一个很棒的特性,经常被忽视。我喜欢的一个例子是:[{a: 1},{b: 2},{c: 3}].inject(:merge) => {:a=>1, :b=>2, :c=>3}
。 - Cary Swovelandavg = a.reduce(:+)/a.size.to_f
[ a.select { |e| e < avg }.max, a.select { |e| e > avg }.min ]
avg = a.reduce(:+)/a.size.to_f
b = (a + [avg]).uniq.sort
i = b.index(avg)
[ b[i-1], b[i+1] ]
b=a+[avg]
可以避免污染原始数组。同时注意,原始数组中只需要两个元素即可。对于猜测需求和实现加1分。 - Phrogz
[1,2,3]
的平均值不是6
,而是2
。总和是6
。那么1
和3
如何接近于6
或2
呢?请使用准确的术语和细节进行编辑。如果数组恰好包含平均值怎么办?三个值等于平均值? - Phrogz[1,2,3,4,5]
和[1,2,3,3,4,5]
? - Cary Swovelandruby
的方式来实现 :) - sameera207