简体   繁体   English

查找最接近数组平均值的元素

[英]Find element(s) closest to average of array

What would be a 'ruby' way to do the following; 做以下事情的“红宝石”方式是什么? I'm still thinking in more imperative style programming and not really adapting to thinking in ruby. 我仍然在考虑更多命令式的风格编程,而不是真正适应红宝石的思考。 What I want to do is find the closest element in size to the average of an array, for example, consider the following array 我想要做的是找到与数组平均值最接近的元素,例如,考虑以下数组

[1,2,3] 

The average is 2.0. 平均值是2.0。 The method I want to write returns the element closest to the average from above and below it, in this case 1 and 3. 我想写的方法返回最接近平均值的元素,在这种情况下是1和3。

Another example will illustrate this better: 另一个例子将更好地说明这一点

[10,20,50,33,22] avg is 27.0 method would return 22 and 33.

This is not the most efficient, but it is (in my humble opinion) rather Ruby-esque. 这不是最有效的,但它(以我的拙见)相当于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 

If you really want the n closest items, then: 如果你真的想要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] 

How this Works 这是怎么回事

avg = inject(0.0,:+) / length
is shorthand for: 是简写:
avg = self.inject(0.0){ |sum,n| sum+n } / self.length
I start off with a value of 0.0 instead of 0 to ensure that the sum will be a floating point number, so that dividing by the length does not give me an integer-rounded value. 我从值0.0而不是0以确保总和将是一个浮点数,因此除以长度不会给我一个整数舍入值。

sort_by{ |v| (v-avg).abs }
sorts the array based on the difference between the number and average (lowest to highest), and then: 根据数字和平均值(从最低到最高)之间的差异对数组进行排序,然后:
[0,results]
selects the first results number of entries from that array. 从该数组中选择第一个结果条目数。

I assume that what is desired is the largest element of the array that is smaller than the average and the smallest value of the array that is larger than the average. 我假设所需要的是数组中最大的元素小于平均值,并且该数组的最小值大于平均值。 Such values exist if and only if the array has at least two elements and they are not all the same. 当且仅当数组具有至少两个元素且它们不完全相同时,才存在这样的值。 Assuming that condition applies, we need only convert it from words to symbols: 假设条件适用,我们只需要将它从单词转换为符号:

avg = a.reduce(:+)/a.size.to_f
[ a.select { |e| e < avg }.max, a.select { |e| e > avg }.min ]

Another way, somewhat less efficient: 另一种方式,效率稍低:

avg = a.reduce(:+)/a.size.to_f
b = (a + [avg]).uniq.sort
i = b.index(avg)
[ b[i-1], b[i+1] ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM