-
Notifications
You must be signed in to change notification settings - Fork 0
/
kdtree.rb
46 lines (35 loc) · 1.22 KB
/
kdtree.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class KDTree
attr_accessor :left, :right, :data, :field
def initialize(points, fields, depth = 0)
self.field = fields[(depth % fields.size) - 1]
if points.size == 1
self.data = points.first
return
end
points.qsort_by!(field)
median_index = (points.size / 2).to_i - 1
self.data = points[median_index]
self.left = KDTree.new(points[0..median_index-1], fields, depth + 1) unless median_index < 1
self.right = KDTree.new(points[median_index+1..-1], fields, depth + 1) unless median_index + 1 >= points.size
end
# Получение пользователей по диапазонам значений полей
#
# range - Hash диапазонов для каждого поля
#
# Returns Array
def query(range = {})
self.class._query(range, self)
end
private
def self._query(range, node)
field = node.field
median = node.data.send(field)
result = []
result += _query(range, node.left) if node.left && median >= range[field].first
result += _query(range, node.right) if node.right && (median <= range[field].last)
if range.keys.all? {|field| range[field].include? node.data.send(field) }
result << node.data
end
result
end
end