[英]Find the closest value in multidimensional arrays with ruby
I need to find the closest values from a set multidimensional arrays, here is the example: 我需要从一组多维数组中找到最接近的值,这是示例:
a = [[a,b,1,2,3],[a,b,5,6,7],[a,b,8,9,10],[c,d,1,2,9],[c,d,1,7,8]]
I want to search the value closest to 1.8 from the overall arrays that contain the same elements in the first 2 index. 我想从在前2个索引中包含相同元素的整个数组中搜索最接近1.8的值。 My expected result is this:
我的预期结果是这样的:
a = [[a,b,1,2,3],[c,d,1,2,9]]
Any ideas? 有任何想法吗? Thanks!
谢谢!
a = [[:a, :b, 1, 2, 3], [:a, :b, 5, 6, 7], [:a, :b, 8, 9, 10], [:c, :d, 1, 2, 9], [:c, :d, 1, 7, 8]]
a.
group_by {|a, b, *_| [a, b] }.
map {|_k, v|
v.min_by {|_, _, *nums|
nums.map {|num| (1.8 - num).abs }.min }}
# => [[:a, :b, 1, 2, 3], [:c, :d, 1, 2, 9]]
map
to v
map
到v
1.8
, so we only have to consider the minimal distance of the three 1.8
绝对差最小的元素的数组,因此我们仅需考虑三个元素之间的最小距离 Assumption 假设
In view of your comment, my understanding is that if: 鉴于您的评论,我的理解是:
a = [[:a, :b, 2], [:a, :b, 3], [:c, :d, 1], [:c, :d, 4]]
and the target value is 1.8
, the desired result is: 且目标值为
1.8
,则预期结果为:
[[:a, :b, 2]]
and not: 并不是:
[[:a, :b, 2], [:c, :d, 1]]
as the "closest value" is 2
and 因为“最接近的值”是
2
,
[[:c, :d, 1], [:c, :d, 4]].flatten.include?(2) #=> false
(At the end, however, I offer a solution for the case where "closest "value" is to be obtained for every group of elements having the same first two elements.) (但是,最后,我为要为具有相同的前两个元素的每组元素获得“最接近的”值的情况提供解决方案。)
Code 码
If my assumption is correct, obtaining the desired result is simple: 如果我的假设是正确的,则获得所需结果很简单:
def extract_closest(a, target)
closest = a.flatten.
select { |e| e.respond_to?(:abs) }.
min_by { |e| (e.to_f-target).abs }
a.select { |e| e.include?(closest) }.uniq { |e| e[0,2] }
end
Examples 例子
target = 1.8
a1 = [[:a, :b, 1, 2, 3], [:a, :b, 5, 6, 7], [:a, :b, 8, 9, 2],
[:c, :d, 1, 2, 9], [:c, :d, 1, 7, 8]]
(Notice that I've changed the last element of a1[2]
from the example.) (注意,我已从示例中更改了
a1[2]
的最后一个元素。)
extract_closest(a1, target)
#=> [[:a, :b, 1, 2, 3], [:c, :d, 1, 2, 9]]
a2 = [[:a, :b, 1, 2, 3], [:a, :b, 5, 6, 7], [:a, :b, 8, 9, 2],
[:c, :d, 1, 3, 9], [:c, :d, 1, 7, 8]]
extract_closest(a2, target)
#=> [[:a, :b, 1, 2, 3]]
Explanation 说明
For the first example above, the steps are as follows: 对于上面的第一个示例,步骤如下:
b = a1.flatten
#=> [:a, :b, 1, 2, 3, :a, :b, 5, 6, 7, :a, :b, 8, 9, 10,
# :c, :d, 1, 2, 9, :c, :d, 1, 7, 8]
c = b.select { |e| e.respond_to?(:-) }
#=> [1, 2, 3, 5, 6, 7, 8, 9, 10, 1, 2, 9, 1, 7, 8]
closest = c.min_by { |e| (e.to_f-target).abs }
#=> 2
enum = a.select
#=> #<Enumerator: [[:a, :b, 1, 2, 3], [:a, :b, 5, 6, 7],
# [:a, :b, 8, 9, 10], [:c, :d, 1, 2, 9], [:c, :d, 1, 7, 8]]
# :select>
e = enum.next
#=> [:a, :b, 1, 2, 3]
e.include?(closest)
#=> [:a, :b, 1, 2, 3].include?(2) => true
so [:a, :b, 1, 2, 3]
is selected. 因此选择了
[:a, :b, 1, 2, 3]
。
e = enum.next
#=> [:a, :b, 5, 6, 7]
e.include?(closest)
#=> [:a, :b, 5, 6, 7].include?(2) #=> false
so [:a, :b, 5, 6, 7]
is not select. 因此未选择
[:a, :b, 5, 6, 7]
。 The remaining elements of enum
are processed similarly, resulting in a return value of: enum
的其余元素的处理方式类似,返回值为:
f = [[:a, :b, 1, 2, 3], [:a, :b, 8, 9, 2], [:c, :d, 1, 2, 9]]
Lastly, we need only one of the first two elements of f
, so: 最后,我们只需要
f
的前两个元素之一,所以:
f.uniq { |e| e[0,2] }
#=> [[:a, :b, 1, 2, 3], [:c, :d, 1, 2, 9]]
Alternative assumption 替代假设
If a "closest "value" is to be obtained for every group of elements having the same first two elements. In addition, to respond to your comment, I'll permit any of the elements of each array to be any object: 如果要为每组具有相同的前两个元素的元素获取“最接近的”值,另外,为了回应您的评论,我将允许每个数组的任何元素为任何对象:
def extract_closest(a, target)
a.each_with_object({}) do |e,h|
min_diff = e[2..-1].select { |n| n.respond_to?(:abs) }.
map { |n| (n.to_f-target).abs }.min
h.update(e[0,2]=>[min_diff, e]) do |_,(omin,oe),(nmin,ne)|
(nmin < omin) ? [nmin, ne] : [omin, oe]
end
end.values.map(&:last)
end
target = 1.8
a3 = [[:a, :b, 1, 2, :c], [:a, :b, 5, "c", 7], [:a, :b, 8, 9, [1,2]],
[:c, :d, 1, 3, {e: 1.8}], [:c, :d, 1, 7, "8"]]
extract_closest(a3, target)
#=> [[:a, :b, 1, 2, :c], [:c, :d, 1, 3, {:e=>1.8}]]
This uses the form of Hash#update (aka merge!
) that uses a block to determine the value of keys that are present in both hashes being merged. 这使用Hash#update的形式(又名
merge!
),该形式使用一个块来确定要合并的两个哈希中存在的键的值。
Explanation for alternative assumption 替代假设的解释
For the example given: 对于给出的示例:
enum0 = a3.each_with_object({})
#=> #<Enumerator: [[:a, :b, 1, 2, :c], [:a, :b, 5, "c", 7],
# [:a, :b, 8, 9, [1, 2]], [:c, :d, 1, 3, {:e=>1.8}],
# [:c, :d, 1, 7, "8"]]:each_with_object({})>
e,h = enum0.next
#=> [[:a, :b, 1, 2, :c], {}]
e #=> [:a, :b, 1, 2, :c]
h #=> {}
b = e[2..-1].select { |n| n.respond_to?(:abs) }
#=> [1, 2]
c = b.map { |n| (n.to_f-target).abs }
#=> [0.8, 0.2]
min_diff = c.min
#=> 0.2
h.update(e[0,2]=>[min_diff, e]) do |_,(omin,oe),(nmin,ne)|
(nmin < omin) ? [nmin, ne] : [omin, oe]
end
#=> {}.update([:a, :b]=>[0.2, [:a, :b, 1, 2, :c]])
#=> {[:a, :b]=>[0.2, [:a, :b, 1, 2, :c]]}
as {}
does not contain the key [:a, :b]
, update
's block is not called upon. 由于
{}
不包含键[:a, :b]
,因此不会调用update
的块。 Note that update
returns the updated value of h
. 请注意,
update
返回h
的更新值。
e,h = enum0.next
#=> [[:a, :b, 5, "c", 7],
# {[:a, :b]=>[0.2, [:a, :b, 1, 2, :c]]}]
b = e[2..-1].select { |n| n.respond_to?(:abs) }
#=> [5, 7]
c = b.map { |n| (n.to_f-target).abs }
#=> [3.2, 5.2]
min_diff = c.min
#=> 3.2
h.update(e[0,2]=>[min_diff, e]) do |_,(omin,oe),(nmin,ne)|
(nmin < omin) ? [nmin, ne] : [omin, oe]
end
update
first considers: update
首先考虑:
h.update(e[0,2]=>[min_diff, e])
#=> {[:a, :b]=>[0.2, [:a, :b, 1, 2, :c]]}.
# update([:a, :b]=> [3.2, [:a, :b, 5, "c", 7]])
As both hashes being merged are found to have the key [:a, :b]
, update
's block is called upon to determine the value of that key in the merged hash: 由于发现两个合并的散列都具有键
[:a, :b]
,因此将调用update
的块以确定合并散列中该键的值:
# do |_,(0.2, [:a, :b, 1, 2, :c]), (3.2, [:a, :b, 5, "c", 7])|
# (3.2 < 0.2) ? [3.2, [:a, :b, 5, "c", 7]] : [0.2, [:a, :b, 1, 2, :c]]
# end
As 3.2 < 0.2 #=> false
, the block returns: 当
3.2 < 0.2 #=> false
,该块返回:
[0.2, [:a, :b, 1, 2, :c]]
for the value of the key [:a, :b]
; 对于键
[:a, :b]
; that is, the value is unchanged. 即,该值不变。
The remaining calculations are similar. 其余计算类似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.