twins 0.0.2 → 0.0.3
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 +4 -4
- data/lib/twins.rb +99 -14
- data/lib/twins/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 330a31cfe1d6f44addbd04f07ef8ce599c1e7ab5
|
4
|
+
data.tar.gz: c34f97c80fc1c360fbbb4c9a6ba4e0b3b34ef180
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a3eec8cb57b212ca23e94b40a26fd077f0552ce0918691dd51994e45b0bf0bcf5d154c0a28c38a8815959db19e8388cd53625942fa488d6aa08960d69303422
|
7
|
+
data.tar.gz: f6c9119803bdb1661d57433088b3f6454d14da1720428cf94752573efd61ec8da020e0b2d1d7efd362bd127394af3f3de076a891c244c7e4b88becc6bf35c1cd
|
data/lib/twins.rb
CHANGED
@@ -3,34 +3,32 @@ require 'twins/utilities'
|
|
3
3
|
|
4
4
|
module Twins
|
5
5
|
|
6
|
-
#
|
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 [
|
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.
|
13
|
-
|
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
|
-
|
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
|
-
|
26
|
-
|
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(
|
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 =
|
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
|
data/lib/twins/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2014-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|