closest_neighbours 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c924621de30b545235ce5ee7eaf16f3a22f642355d61284b4a5a3550e195075
4
- data.tar.gz: a4511b796aa75101d38059eb960f610ce06ab87d22625dab7af2ea805f81ec5f
3
+ metadata.gz: 1dc9ec134c754981b57d69366f513ec4768678472b18d5cf79c61513bd625b12
4
+ data.tar.gz: 27c1a7596b2708fab789d7e695d39455d104b7de76f00e0271bd6c3a4d3dec46
5
5
  SHA512:
6
- metadata.gz: 1586442b671d00ff96f54bdce79419eebd21b29ab760524ea98454483cf191265e374c7a263351f37d22dd846ee0f78077432ac58c14f00c8d9c518e9dabbf42
7
- data.tar.gz: e828070ebd738c968ad971d29680b689993796e5c690b1b764648a6a9e990b504ce6a65b981b89c97a8c8f08cd7adddb641bd384efbc78936ed935ca9d3ba76e
6
+ metadata.gz: c01f230fb3bc47584b249804c216d55bb16a2cff8dceecb187dd6a82d0bb7d860a6032a08c278f0a5ecaf1910100a36c3e7df5a3dc849d0bd2a34a29b5fd1b7b
7
+ data.tar.gz: 2bf2f4574fc4b2f0db9fbd36a7485bc790418b3e9b67c87570f827694ce5e0ab5fb9cf87343c663b6ddc8866abaf13fea9e16b6768c501531e368e63c2f54fef
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- closest_neighbours (0.1.0)
4
+ closest_neighbours (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # ClosestNeighbours
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/closest_neighbours.svg)](https://badge.fury.io/rb/closest_neighbours)
4
+ [![Build Status](https://app.travis-ci.com/aussiDavid/closest_neighbours.svg?branch=main)](https://app.travis-ci.com/aussiDavid/closest_neighbours)
5
+
3
6
  This gem takes an array of elements, groups them by their ordered closest neighbors into `n` groups.
4
7
 
5
8
  **Origin Story:**
@@ -69,11 +72,17 @@ require 'closest_neighbours'
69
72
  Use the module:
70
73
 
71
74
  ```ruby
72
- ClosestNeighbours.group(2, [1, 2, 3, 4])
75
+ ClosestNeighbours.group(2, [1, 4, 3, 2])
73
76
  # => [[1, 2], [3, 4]]
74
- ClosestNeighbours.group(3, [10.days.ago, 9.days.ago, 1.day.ago])
77
+ ClosestNeighbours.group(2, [10.days.ago, 9.days.ago, 1.day.ago])
75
78
  # => [[10.days.ago, 9.days.ago], [1.day.ago]]
79
+ ```
80
+
81
+ `ClosestNeighbours.ordered_group` allows you to squeeze additional performance out of the module by providing an ordered set of inputs. If in doubt, use `ClosestNeighbours.group`.
76
82
 
83
+ ```ruby
84
+ ClosestNeighbours.ordered_group(2, [1, 2, 3, 4])
85
+ # => [[1, 2], [3, 4]]
77
86
  ```
78
87
 
79
88
  ## Development
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClosestNeighbours
4
+ # Error when an 1 or more element in an enumerable are not comparable with each other
5
+ class IncomparableElementError < StandardError
6
+ end
7
+ end
@@ -1,35 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClosestNeighbours
4
- # Match array of times up into groups that are the closest to each other
5
- class Ordered
6
- def initialize(groups = 1, data = [])
4
+ # Split an Enumerable into specified number of groups containing the closest elements in each group.
5
+ class Grouper
6
+ def initialize(orderer: DefaultOrder.new)
7
+ @orderer = orderer
8
+ end
9
+
10
+ def call(groups = 1, data = [])
7
11
  @groups = groups
8
12
  @data = data
9
- end
10
13
 
11
- def call
12
14
  validate!
13
15
 
14
16
  if groups >= size
15
17
  wraped_data + blanks
16
18
  else
17
- ranges.map { |range| sorted_data[range] }
19
+ ranges.map { |range| ordered_data[range] }
18
20
  end
19
21
  end
20
22
 
21
23
  private
22
24
 
23
- attr_reader :groups, :data
25
+ attr_reader :groups, :data, :orderer
24
26
 
25
27
  def validate!
26
28
  raise NonIntegerGroupsError unless groups.is_a? Integer
27
29
  raise NonEnumberableArgumentError unless data.is_a? Enumerable
28
30
  raise InsufficientGroupsError if groups < 1
31
+ raise IncomparableElementError unless comparable_elements?
29
32
  end
30
33
 
31
34
  def size
32
- data.to_a.size
35
+ data.count
33
36
  end
34
37
 
35
38
  def blanks
@@ -41,7 +44,7 @@ module ClosestNeighbours
41
44
  end
42
45
 
43
46
  def wraped_data
44
- sorted_data.map { |x| [x] }
47
+ ordered_data.map { |x| [x] }
45
48
  end
46
49
 
47
50
  def ranges
@@ -59,7 +62,7 @@ module ClosestNeighbours
59
62
  end
60
63
 
61
64
  def differences_between_each_pair
62
- sorted_data.each_cons(2).map { |(a, b)| b - a }
65
+ ordered_data.each_cons(2).map { |(a, b)| b - a }
63
66
  end
64
67
 
65
68
  def differences_with_indices
@@ -69,8 +72,12 @@ module ClosestNeighbours
69
72
  .reverse
70
73
  end
71
74
 
72
- def sorted_data
73
- @sorted_data ||= data.sort
75
+ def ordered_data
76
+ @ordered_data ||= orderer.call(data)
77
+ end
78
+
79
+ def comparable_elements?
80
+ data.all? { |e| data.first <=> e }
74
81
  end
75
82
  end
76
83
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClosestNeighbours
4
+ # The default order of enumberales
5
+ class DefaultOrder
6
+ def call(data = [])
7
+ data.to_a
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClosestNeighbours
4
+ # Sort an enumerator
5
+ class SortedOrder
6
+ def call(data = [])
7
+ data.sort
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module ClosestNeighbours
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -1,17 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'closest_neighbours/version'
4
- require 'closest_neighbours/ordered'
4
+ require 'closest_neighbours/grouper'
5
+
6
+ # Plugable Roles
7
+ require 'closest_neighbours/orderers/sorted_order'
8
+ require 'closest_neighbours/orderers/default_order'
5
9
 
6
10
  # Errors
7
11
  require 'closest_neighbours/errors/non_enumberable_argument_error'
8
12
  require 'closest_neighbours/errors/insufficient_groups_error'
9
13
  require 'closest_neighbours/errors/non_integer_groups_error'
14
+ require 'closest_neighbours/errors/incomparable_element_error'
10
15
 
11
- # Takes an array of elements, groups them by their ordered closest neighbors into n groups
16
+ # Top level model for Closest Neighbours gem
12
17
  module ClosestNeighbours
13
18
  #
14
- # Split an Enumerable into specified number of groups containing the closest elements in each group.
19
+ # Split an Enumerable into specified number of groups containing the closest elements in each group using the most general purpose algorithm.
15
20
  #
16
21
  # @example
17
22
  #
@@ -19,11 +24,28 @@ module ClosestNeighbours
19
24
  # # => [[2, 5], [10, 11]]
20
25
  #
21
26
  # @param [Integer] groups The number of groups to create
22
- # @param [Array|Set|Enumerable] data The data set of items to group
27
+ # @param [Enumerable] data The data set of items to group
23
28
  #
24
29
  # @return [Array] An array of `groups` groups
25
30
  #
26
31
  def self.group(groups, data)
27
- Ordered.new(groups, data).call
32
+ Grouper.new(orderer: SortedOrder.new).call(groups, data)
33
+ end
34
+
35
+ #
36
+ # Split a sorted Enumerable into specified number of groups containing the closest elements in each group.
37
+ #
38
+ # @example
39
+ #
40
+ # ClosestNeighbours.ordered_group(2, [2, 5, 10, 11])
41
+ # # => [[2, 5], [10, 11]]
42
+ #
43
+ # @param [Integer] groups The number of groups to create
44
+ # @param [Enumerable] ordered_data The data set of items to group
45
+ #
46
+ # @return [Array] An array of `groups` groups
47
+ #
48
+ def self.ordered_group(groups, ordered_data)
49
+ Grouper.new(orderer: DefaultOrder.new).call(groups, ordered_data)
28
50
  end
29
51
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closest_neighbours
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Milanese
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-15 00:00:00.000000000 Z
11
+ date: 2021-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -132,10 +132,13 @@ files:
132
132
  - bin/setup
133
133
  - closest_neighbours.gemspec
134
134
  - lib/closest_neighbours.rb
135
+ - lib/closest_neighbours/errors/incomparable_element_error.rb
135
136
  - lib/closest_neighbours/errors/insufficient_groups_error.rb
136
137
  - lib/closest_neighbours/errors/non_enumberable_argument_error.rb
137
138
  - lib/closest_neighbours/errors/non_integer_groups_error.rb
138
- - lib/closest_neighbours/ordered.rb
139
+ - lib/closest_neighbours/grouper.rb
140
+ - lib/closest_neighbours/orderers/default_order.rb
141
+ - lib/closest_neighbours/orderers/sorted_order.rb
139
142
  - lib/closest_neighbours/version.rb
140
143
  homepage: https://github.com/aussidavid/closest_neighbours
141
144
  licenses: