twins 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/twins.rb +99 -14
  3. data/lib/twins/version.rb +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20e9e6421c19c6abccbb7f121b1ba3a36ae56a7e
4
- data.tar.gz: 660fdd54b8e6acb0d2a947c329e0293d147919af
3
+ metadata.gz: 330a31cfe1d6f44addbd04f07ef8ce599c1e7ab5
4
+ data.tar.gz: c34f97c80fc1c360fbbb4c9a6ba4e0b3b34ef180
5
5
  SHA512:
6
- metadata.gz: e2dababf31cb5d844ae4ff9588758e27538fad29fd086354a6f43e66640647f0c8339c838a17c34515339bd6191286ea6618e4fd042a82bee70140980c905710
7
- data.tar.gz: fd4442cd82dbc5d41df4d605d724c03c3070e8e363dd4b0b97b54454e298b059289de248e1c6284b6109efdb1812f580f2977af6bb48a00dbb1da2c08b05aefc
6
+ metadata.gz: 7a3eec8cb57b212ca23e94b40a26fd077f0552ce0918691dd51994e45b0bf0bcf5d154c0a28c38a8815959db19e8388cd53625942fa488d6aa08960d69303422
7
+ data.tar.gz: f6c9119803bdb1661d57433088b3f6454d14da1720428cf94752573efd61ec8da020e0b2d1d7efd362bd127394af3f3de076a891c244c7e4b88becc6bf35c1cd
@@ -3,34 +3,32 @@ require 'twins/utilities'
3
3
 
4
4
  module Twins
5
5
 
6
- # @param collection [Enumerable] A collection of Hash objects
6
+ # Consolidates keys with mode or lowest distance
7
+ #
8
+ # @param collection [Enumerable] A collection of Hash or Hash-like objects
7
9
  # @param options [Hash]
8
- # @return [Hash, Nil]
10
+ # @return [HashWithIndifferentAccess, Nil]
9
11
  def consolidate(collection, options = {})
10
12
  return nil unless collection.any?
13
+ ensure_collection_uniformity!(collection)
11
14
 
12
- if collection.all? { |e| e.is_a?(Hash) }
13
- # noop
14
- elsif collection.all? { |e| e.is_a?(collection.first.class) }
15
- collection = collection.map do |element|
16
- Hash[element.instance_variables.map { |name| [name.to_s.sub(/\A@/, ''), element.instance_variable_get(name)] }]
17
- end
15
+ if collection.first.is_a?(Hash)
16
+ indiff_collection = collection
18
17
  else
19
- raise ArgumentError, "The collection's elements must all be of the same Class"
18
+ indiff_collection = collection.map { |element| element.to_hash }
20
19
  end
21
20
 
22
21
  options = options.with_indifferent_access
23
22
  consolidated = Hash.new
24
23
 
25
- collection.each do |hash|
26
- hash.each_pair do |key, value|
27
-
24
+ indiff_collection.each do |element|
25
+ element.each_pair do |key, value|
28
26
  # Recursively consolidate nested hashes
29
27
  if value.is_a?(Hash) && !consolidated[key]
30
- consolidated[key] = consolidate(collection.map { |element| element[key] })
28
+ consolidated[key] = consolidate(indiff_collection.map { |el| el[key] })
31
29
  else
32
30
  # Filter elements without a given key to avoid unintentionally nil values
33
- values = collection.select { |element| element.has_key?(key) }.map { |element| element[key] }
31
+ values = indiff_collection.select { |el| el.has_key?(key) }.map { |el| el[key] }
34
32
 
35
33
  if options[:priority].try(:[], key)
36
34
  # Compute each element's distance from the given priority
@@ -49,4 +47,91 @@ module Twins
49
47
  consolidated.with_indifferent_access
50
48
  end
51
49
  module_function :consolidate
50
+
51
+ # Find element with the highest count of modes or the lowest overall distances
52
+ #
53
+ # @param collection [Enumerable] A collection of Hash or Hash-like objects
54
+ # @param options [Hash]
55
+ # @return [Object, Nil]
56
+ def pick(collection, options = {})
57
+ return nil unless collection.any?
58
+ ensure_collection_uniformity!(collection)
59
+
60
+ options = options.with_indifferent_access
61
+
62
+ if options[:priority]
63
+ pick_by_priority(collection, options[:priority])
64
+ else
65
+ pick_by_mode(collection)
66
+ end
67
+ end
68
+ module_function :pick
69
+
70
+ # Find the element with the highest count of modes
71
+ #
72
+ # @param collection [Enumerable]
73
+ # @return [Object, Nil]
74
+ def pick_by_mode(collection)
75
+ return nil unless collection.any?
76
+
77
+ if collection.first.is_a?(Hash)
78
+ indiff_collection = collection
79
+ else
80
+ indiff_collection = collection.map { |element| element.to_hash.with_indifferent_access }
81
+ end
82
+
83
+ collection.max_by do |element|
84
+ if collection.first.is_a?(Hash)
85
+ indiff_element = element
86
+ else
87
+ indiff_element = element.to_hash.with_indifferent_access
88
+ end
89
+
90
+ # Build a map of modes for each existing key
91
+ modes = indiff_element.map do |key, value|
92
+ # Filter elements without a given key to avoid unintentionally nil values
93
+ values = indiff_collection.select { |el| el.has_key?(key) }.map { |el| el[key] }
94
+ [key, Twins::Utilities.mode(values)]
95
+ end
96
+ modes = Hash[modes]
97
+
98
+ # Count the number of modes present in element
99
+ modes.select { |key, mode| indiff_element[key] == mode }.count
100
+ end
101
+ end
102
+ module_function :pick_by_mode
103
+
104
+ # Find the element with the lowest overall distances
105
+ #
106
+ # @param collection [Enumerable]
107
+ # @param options [Hash]
108
+ # @return [Object, Nil]
109
+ def pick_by_priority(collection, priorities)
110
+ return nil unless collection.any?
111
+ raise ArgumentError unless priorities.is_a?(Hash)
112
+
113
+ collection.min_by do |element|
114
+ if collection.first.is_a?(Hash)
115
+ indiff_element = element
116
+ else
117
+ indiff_element = element.to_hash.with_indifferent_access
118
+ end
119
+
120
+ priorities.map do |key, value|
121
+ Twins::Utilities.distance(value, indiff_element[key])
122
+ end.sum
123
+ end
124
+ end
125
+ module_function :pick_by_priority
126
+
127
+ # @private
128
+ def ensure_collection_uniformity!(collection)
129
+ if collection.none? { |e| e.is_a?(Hash) || e.is_a?(collection.first.class) }
130
+ raise ArgumentError, "The collection's elements must all be of the same Class"
131
+ elsif collection.none? { |e| e.respond_to?(:to_hash) }
132
+ raise ArgumentError, "The collection's elements must respond to '#to_hash'"
133
+ end
134
+ end
135
+ module_function :ensure_collection_uniformity!
136
+ private_class_method :ensure_collection_uniformity!
52
137
  end
@@ -1,3 +1,3 @@
1
1
  module Twins
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twins
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philippe Dionne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-25 00:00:00.000000000 Z
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport