immutable-ruby 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/immutable/sorted_set.rb +47 -11
- data/lib/immutable/version.rb +1 -1
- data/spec/lib/immutable/set/sorting_spec.rb +8 -2
- data/spec/lib/immutable/sorted_set/above_spec.rb +2 -2
- data/spec/lib/immutable/sorted_set/below_spec.rb +2 -2
- data/spec/lib/immutable/sorted_set/between_spec.rb +2 -2
- data/spec/lib/immutable/sorted_set/from_spec.rb +2 -2
- data/spec/lib/immutable/sorted_set/map_spec.rb +8 -0
- data/spec/lib/immutable/sorted_set/new_spec.rb +66 -0
- data/spec/lib/immutable/sorted_set/sorting_spec.rb +12 -0
- data/spec/lib/immutable/sorted_set/union_spec.rb +31 -0
- data/spec/lib/immutable/sorted_set/up_to_spec.rb +2 -2
- data/spec/lib/immutable/sorted_set/util_spec.rb +48 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f0b9336a378ad7d4e2cf98b8977c0dbac13ed74b
|
|
4
|
+
data.tar.gz: 2ec6d56a86049914a7c3e9807277a6134f5f4842
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02a4a9fa583aa94d5a609b8654247d486e41c51efcf0e3f3447ec47f6fd31e2f204e65dc906b6c6b82341dfdcc826b1a9ed55d9a4c8022e88508068999859d2f
|
|
7
|
+
data.tar.gz: 4246f4d3457284cd82c13ed20b92f1b8d00e9cad02d30a0909f8f9d4194e331deac73fbaf5ebbaa1a4f395199c68f90cfdfef68403ac1c6a81edaf5b5e5878dc
|
data/lib/immutable/sorted_set.rb
CHANGED
|
@@ -76,21 +76,43 @@ module Immutable
|
|
|
76
76
|
def alloc(node)
|
|
77
77
|
allocate.tap { |s| s.instance_variable_set(:@node, node) }.freeze
|
|
78
78
|
end
|
|
79
|
+
|
|
80
|
+
# @private
|
|
81
|
+
# Unfortunately, Ruby's stdlib doesn't do this for us
|
|
82
|
+
# array must be sorted
|
|
83
|
+
def uniq_by_comparator!(array, comparator)
|
|
84
|
+
to_check, shift, sz, prev_obj = 1, 0, array.size, array[0]
|
|
85
|
+
while to_check < sz
|
|
86
|
+
next_obj = array[to_check]
|
|
87
|
+
if comparator.call(prev_obj, next_obj) == 0
|
|
88
|
+
shift += 1
|
|
89
|
+
else
|
|
90
|
+
if shift > 0
|
|
91
|
+
array[to_check - shift] = next_obj
|
|
92
|
+
end
|
|
93
|
+
prev_obj = next_obj
|
|
94
|
+
end
|
|
95
|
+
to_check += 1
|
|
96
|
+
end
|
|
97
|
+
array.pop(shift) if shift > 0
|
|
98
|
+
end
|
|
79
99
|
end
|
|
80
100
|
|
|
81
101
|
def initialize(items=[], &block)
|
|
82
102
|
items = items.to_a
|
|
83
103
|
if block
|
|
84
104
|
if block.arity == 1 || block.arity == -1
|
|
105
|
+
items = items.uniq(&block)
|
|
106
|
+
items.sort_by!(&block)
|
|
85
107
|
comparator = lambda { |a,b| block.call(a) <=> block.call(b) }
|
|
86
|
-
items = items.sort_by(&block)
|
|
87
108
|
else
|
|
88
|
-
comparator = block
|
|
89
109
|
items = items.sort(&block)
|
|
110
|
+
SortedSet.uniq_by_comparator!(items, block)
|
|
111
|
+
comparator = block
|
|
90
112
|
end
|
|
91
113
|
@node = AVLNode.from_items(items, comparator)
|
|
92
114
|
else
|
|
93
|
-
@node = PlainAVLNode.from_items(items.sort)
|
|
115
|
+
@node = PlainAVLNode.from_items(items.uniq.sort!)
|
|
94
116
|
end
|
|
95
117
|
freeze
|
|
96
118
|
end
|
|
@@ -476,9 +498,11 @@ module Immutable
|
|
|
476
498
|
def sort(&block)
|
|
477
499
|
if block
|
|
478
500
|
self.class.new(self.to_a, &block)
|
|
501
|
+
elsif @node.natural_order?
|
|
502
|
+
self
|
|
479
503
|
else
|
|
480
|
-
self.class.new(self
|
|
481
|
-
end
|
|
504
|
+
self.class.new(self)
|
|
505
|
+
end
|
|
482
506
|
end
|
|
483
507
|
alias :sort_by :sort
|
|
484
508
|
|
|
@@ -990,7 +1014,8 @@ module Immutable
|
|
|
990
1014
|
|
|
991
1015
|
# @private
|
|
992
1016
|
class AVLNode
|
|
993
|
-
def self.from_items(items, comparator, from = 0, to = items.size-1)
|
|
1017
|
+
def self.from_items(items, comparator, from = 0, to = items.size-1)
|
|
1018
|
+
# items must be sorted, without duplicates (as determined by comparator)
|
|
994
1019
|
size = to - from + 1
|
|
995
1020
|
if size >= 3
|
|
996
1021
|
middle = (to + from) / 2
|
|
@@ -1013,8 +1038,12 @@ module Immutable
|
|
|
1013
1038
|
end
|
|
1014
1039
|
attr_reader :item, :left, :right, :height, :size
|
|
1015
1040
|
|
|
1041
|
+
# Used to implement #map
|
|
1042
|
+
# Takes advantage of the fact that Enumerable#map allocates a new Array
|
|
1016
1043
|
def from_items(items)
|
|
1017
|
-
|
|
1044
|
+
items.sort!(&@comparator)
|
|
1045
|
+
SortedSet.uniq_by_comparator!(items, @comparator)
|
|
1046
|
+
AVLNode.from_items(items, @comparator)
|
|
1018
1047
|
end
|
|
1019
1048
|
|
|
1020
1049
|
def natural_order?
|
|
@@ -1374,7 +1403,9 @@ module Immutable
|
|
|
1374
1403
|
end
|
|
1375
1404
|
def bulk_insert(items)
|
|
1376
1405
|
items = items.to_a if !items.is_a?(Array)
|
|
1377
|
-
|
|
1406
|
+
items = items.sort(&@comparator)
|
|
1407
|
+
SortedSet.uniq_by_comparator!(items, @comparator)
|
|
1408
|
+
AVLNode.from_items(items, @comparator)
|
|
1378
1409
|
end
|
|
1379
1410
|
def bulk_delete(items); self; end
|
|
1380
1411
|
def keep_only(items); self; end
|
|
@@ -1397,7 +1428,8 @@ module Immutable
|
|
|
1397
1428
|
# AVL node which does not use a comparator function; it keeps items sorted
|
|
1398
1429
|
# in their natural order
|
|
1399
1430
|
class PlainAVLNode < AVLNode
|
|
1400
|
-
def self.from_items(items, from = 0, to = items.size-1)
|
|
1431
|
+
def self.from_items(items, from = 0, to = items.size-1)
|
|
1432
|
+
# items must be sorted, with no duplicates
|
|
1401
1433
|
size = to - from + 1
|
|
1402
1434
|
if size >= 3
|
|
1403
1435
|
middle = (to + from) / 2
|
|
@@ -1418,8 +1450,12 @@ module Immutable
|
|
|
1418
1450
|
end
|
|
1419
1451
|
attr_reader :item, :left, :right, :height, :size
|
|
1420
1452
|
|
|
1453
|
+
# Used to implement #map
|
|
1454
|
+
# Takes advantage of the fact that Enumerable#map allocates a new Array
|
|
1421
1455
|
def from_items(items)
|
|
1422
|
-
|
|
1456
|
+
items.uniq!
|
|
1457
|
+
items.sort!
|
|
1458
|
+
PlainAVLNode.from_items(items)
|
|
1423
1459
|
end
|
|
1424
1460
|
|
|
1425
1461
|
def natural_order?
|
|
@@ -1447,7 +1483,7 @@ module Immutable
|
|
|
1447
1483
|
end
|
|
1448
1484
|
def bulk_insert(items)
|
|
1449
1485
|
items = items.to_a if !items.is_a?(Array)
|
|
1450
|
-
PlainAVLNode.from_items(items.sort)
|
|
1486
|
+
PlainAVLNode.from_items(items.uniq.sort!)
|
|
1451
1487
|
end
|
|
1452
1488
|
end
|
|
1453
1489
|
|
data/lib/immutable/version.rb
CHANGED
|
@@ -47,13 +47,19 @@ describe Immutable::Set do
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
describe "#sort_by" do
|
|
50
|
-
|
|
50
|
+
# originally this test checked that #sort_by only called the block once
|
|
51
|
+
# for each item
|
|
52
|
+
# however, when initializing a SortedSet, we need to make sure that it
|
|
53
|
+
# does not include any duplicates, and we use the block when checking that
|
|
54
|
+
# the real point here is that the block should not be called an excessive
|
|
55
|
+
# number of times, degrading performance
|
|
56
|
+
it "calls the passed block no more than twice for each item" do
|
|
51
57
|
count = 0
|
|
52
58
|
fn = lambda { |x| count += 1; -x }
|
|
53
59
|
items = 100.times.collect { rand(10000) }.uniq
|
|
54
60
|
|
|
55
61
|
S[*items].sort_by(&fn).to_a.should == items.sort.reverse
|
|
56
|
-
count.should
|
|
62
|
+
count.should <= (items.length * 2)
|
|
57
63
|
end
|
|
58
64
|
end
|
|
59
65
|
end
|
|
@@ -5,7 +5,7 @@ describe Immutable::SortedSet do
|
|
|
5
5
|
context "when called without a block" do
|
|
6
6
|
it "returns a sorted set of all items higher than the argument" do
|
|
7
7
|
100.times do
|
|
8
|
-
items = rand(100).times.collect { rand(1000) }
|
|
8
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
9
9
|
set = SS.new(items)
|
|
10
10
|
threshold = rand(1000)
|
|
11
11
|
result = set.above(threshold)
|
|
@@ -20,7 +20,7 @@ describe Immutable::SortedSet do
|
|
|
20
20
|
context "when called with a block" do
|
|
21
21
|
it "yields all the items higher than the argument" do
|
|
22
22
|
100.times do
|
|
23
|
-
items = rand(100).times.collect { rand(1000) }
|
|
23
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
24
24
|
set = SS.new(items)
|
|
25
25
|
threshold = rand(1000)
|
|
26
26
|
result = []
|
|
@@ -5,7 +5,7 @@ describe Immutable::SortedSet do
|
|
|
5
5
|
context "when called without a block" do
|
|
6
6
|
it "returns a sorted set of all items lower than the argument" do
|
|
7
7
|
100.times do
|
|
8
|
-
items = rand(100).times.collect { rand(1000) }
|
|
8
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
9
9
|
set = SS.new(items)
|
|
10
10
|
threshold = rand(1000)
|
|
11
11
|
result = set.below(threshold)
|
|
@@ -20,7 +20,7 @@ describe Immutable::SortedSet do
|
|
|
20
20
|
context "when called with a block" do
|
|
21
21
|
it "yields all the items lower than the argument" do
|
|
22
22
|
100.times do
|
|
23
|
-
items = rand(100).times.collect { rand(1000) }
|
|
23
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
24
24
|
set = SS.new(items)
|
|
25
25
|
threshold = rand(1000)
|
|
26
26
|
result = []
|
|
@@ -5,7 +5,7 @@ describe Immutable::SortedSet do
|
|
|
5
5
|
context "when called without a block" do
|
|
6
6
|
it "returns a sorted set of all items from the first argument to the second" do
|
|
7
7
|
100.times do
|
|
8
|
-
items = rand(100).times.collect { rand(1000) }
|
|
8
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
9
9
|
set = SS.new(items)
|
|
10
10
|
from,to = [rand(1000),rand(1000)].sort
|
|
11
11
|
result = set.between(from, to)
|
|
@@ -20,7 +20,7 @@ describe Immutable::SortedSet do
|
|
|
20
20
|
context "when called with a block" do
|
|
21
21
|
it "yields all the items lower than the argument" do
|
|
22
22
|
100.times do
|
|
23
|
-
items = rand(100).times.collect { rand(1000) }
|
|
23
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
24
24
|
set = SS.new(items)
|
|
25
25
|
from,to = [rand(1000),rand(1000)].sort
|
|
26
26
|
result = []
|
|
@@ -5,7 +5,7 @@ describe Immutable::SortedSet do
|
|
|
5
5
|
context "when called without a block" do
|
|
6
6
|
it "returns a sorted set of all items equal to or greater than the argument" do
|
|
7
7
|
100.times do
|
|
8
|
-
items = rand(100).times.collect { rand(1000) }
|
|
8
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
9
9
|
set = SS.new(items)
|
|
10
10
|
threshold = rand(1000)
|
|
11
11
|
result = set.from(threshold)
|
|
@@ -20,7 +20,7 @@ describe Immutable::SortedSet do
|
|
|
20
20
|
context "when called with a block" do
|
|
21
21
|
it "yields all the items equal to or greater than than the argument" do
|
|
22
22
|
100.times do
|
|
23
|
-
items = rand(100).times.collect { rand(1000) }
|
|
23
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
24
24
|
set = SS.new(items)
|
|
25
25
|
threshold = rand(1000)
|
|
26
26
|
result = []
|
|
@@ -21,6 +21,10 @@ describe Immutable::SortedSet do
|
|
|
21
21
|
it "returns a new set with the mapped values" do
|
|
22
22
|
sorted_set.send(method, &:downcase).should eql(SS["a", "b", "c"])
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
it "filters out duplicates" do
|
|
26
|
+
sorted_set.send(method) { 'blah' }.should eq(SS['blah'])
|
|
27
|
+
end
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
context "with no block" do
|
|
@@ -37,6 +41,10 @@ describe Immutable::SortedSet do
|
|
|
37
41
|
it "returns a new set with the mapped values" do
|
|
38
42
|
sorted_set.send(method, &:downcase).should == ['c', 'b', 'a']
|
|
39
43
|
end
|
|
44
|
+
|
|
45
|
+
it "filters out duplicates" do
|
|
46
|
+
sorted_set.send(method) { 'blah' }.should eq(SS['blah'])
|
|
47
|
+
end
|
|
40
48
|
end
|
|
41
49
|
end
|
|
42
50
|
end
|
|
@@ -18,6 +18,19 @@ describe Immutable::SortedSet do
|
|
|
18
18
|
sorted_set[2].should be(3)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
it "doesn't mutate the initializer" do
|
|
22
|
+
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
|
|
23
|
+
sorted_set = SS.new(array)
|
|
24
|
+
expect(array).to eq([3,2,1,3,2,1])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "doesn't change if the initializer is later mutated" do
|
|
28
|
+
array = [3,2,1,3,2,1]
|
|
29
|
+
sorted_set = SS.new(array)
|
|
30
|
+
array.clear
|
|
31
|
+
expect(sorted_set.to_a).to eq([1,2,3])
|
|
32
|
+
end
|
|
33
|
+
|
|
21
34
|
it "is amenable to overriding of #initialize" do
|
|
22
35
|
class SnazzySortedSet < Immutable::SortedSet
|
|
23
36
|
def initialize
|
|
@@ -50,6 +63,51 @@ describe Immutable::SortedSet do
|
|
|
50
63
|
sorted_set[1].should be(Object)
|
|
51
64
|
end
|
|
52
65
|
|
|
66
|
+
it "filters out duplicates" do
|
|
67
|
+
sorted_set = SS.new(['a', 'b', 'a', 'c', 'b', 'a', 'c', 'c'])
|
|
68
|
+
expect(sorted_set.size).to be(3)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "when passed a comparator with arity 2" do
|
|
72
|
+
it "still filters out duplicates" do
|
|
73
|
+
sorted_set = SS.new([1,2,7,8,9,10]) { |x,y| (x%7) <=> (y%7) }
|
|
74
|
+
expect(sorted_set.to_a).to eq([7,1,2,10])
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "still doesn't mutate the initializer" do
|
|
78
|
+
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
|
|
79
|
+
sorted_set = SS.new(array) { |x,y| y <=> x }
|
|
80
|
+
expect(array).to eq([3,2,1,3,2,1])
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "still doesn't change if the initializer is later mutated" do
|
|
84
|
+
array = [3,2,1,3,2,1]
|
|
85
|
+
sorted_set = SS.new(array) { |x,y| y <=> x }
|
|
86
|
+
array.clear
|
|
87
|
+
expect(sorted_set.to_a).to eq([3,2,1])
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "when passed a block with arity 1" do
|
|
92
|
+
it "still filters out duplicates" do
|
|
93
|
+
sorted_set = SS.new([1,2,7,8,9,10]) { |x| x % 7 }
|
|
94
|
+
expect(sorted_set.to_a).to eq([7,1,2,10])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "still doesn't mutate the initializer" do
|
|
98
|
+
array = [3,2,1,3,2,1] # this will need to be sorted and duplicates filtered out
|
|
99
|
+
sorted_set = SS.new(array) { |x| x % 7 }
|
|
100
|
+
expect(array).to eq([3,2,1,3,2,1])
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "still doesn't change if the initializer is later mutated" do
|
|
104
|
+
array = [3,2,1,3,2,1]
|
|
105
|
+
sorted_set = SS.new(array) { |x| x % 7 }
|
|
106
|
+
array.clear
|
|
107
|
+
expect(sorted_set.to_a).to eq([1,2,3])
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
53
111
|
context "from a subclass" do
|
|
54
112
|
it "returns a frozen instance of the subclass" do
|
|
55
113
|
subclass = Class.new(Immutable::SortedSet)
|
|
@@ -67,5 +125,13 @@ describe Immutable::SortedSet do
|
|
|
67
125
|
sorted_set[0].should == 'a'
|
|
68
126
|
sorted_set[1].should == 'b'
|
|
69
127
|
end
|
|
128
|
+
|
|
129
|
+
it "filters out duplicate items" do
|
|
130
|
+
sorted_set = SS['a', 'b', 'a', 'c', 'b', 'a', 'c', 'c']
|
|
131
|
+
expect(sorted_set.size).to be(3)
|
|
132
|
+
sorted_set[0].should == 'a'
|
|
133
|
+
sorted_set[1].should == 'b'
|
|
134
|
+
sorted_set[2].should == 'c'
|
|
135
|
+
end
|
|
70
136
|
end
|
|
71
137
|
end
|
|
@@ -41,4 +41,16 @@ describe Immutable::SortedSet do
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
describe :sort do
|
|
46
|
+
context "on a SortedSet with custom sort order" do
|
|
47
|
+
let(:sorted_set) { SS.new([1,2,3,4]) { |x,y| y <=> x }}
|
|
48
|
+
|
|
49
|
+
it "returns a SortedSet with the natural sort order" do
|
|
50
|
+
result = sorted_set.sort
|
|
51
|
+
expect(sorted_set.to_a).to eq([4,3,2,1])
|
|
52
|
+
expect(result.to_a).to eq([1,2,3,4])
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
44
56
|
end
|
|
@@ -24,4 +24,35 @@ describe Immutable::SortedSet do
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
describe :union do
|
|
29
|
+
it "filters out duplicates when passed an Array" do
|
|
30
|
+
sorted_set = SS['A', 'B', 'C', 'D'].union(['A', 'A', 'A', 'C', 'A', 'B', 'E'])
|
|
31
|
+
expect(sorted_set.to_a).to eq(['A', 'B', 'C', 'D', 'E'])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "doesn't mutate an Array which is passed in" do
|
|
35
|
+
array = [3,2,1,3]
|
|
36
|
+
sorted_set = SS[1,2,5].union(array)
|
|
37
|
+
expect(array).to eq([3,2,1,3])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "on a set ordered by a comparator" do
|
|
41
|
+
# Completely different code is executed when #union is called on a SS
|
|
42
|
+
# with a comparator block, so we should repeat all the same tests
|
|
43
|
+
|
|
44
|
+
it "still filters out duplicates when passed an Array" do
|
|
45
|
+
sorted_set = SS.new([1,2,3]) { |x,y| (x%7) <=> (y%7) }
|
|
46
|
+
sorted_set = sorted_set.union([7,8,9])
|
|
47
|
+
expect(sorted_set.to_a).to eq([7,1,2,3])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "still doesn't mutate an Array which is passed in" do
|
|
51
|
+
array = [3,2,1,3]
|
|
52
|
+
sorted_set = SS.new([1,2,5]) { |x,y| y <=> x }
|
|
53
|
+
sorted_set = sorted_set.union(array)
|
|
54
|
+
expect(array).to eq([3,2,1,3])
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
27
58
|
end
|
|
@@ -5,7 +5,7 @@ describe Immutable::SortedSet do
|
|
|
5
5
|
context "when called without a block" do
|
|
6
6
|
it "returns a sorted set of all items equal to or less than the argument" do
|
|
7
7
|
100.times do
|
|
8
|
-
items = rand(100).times.collect { rand(1000) }
|
|
8
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
9
9
|
set = SS.new(items)
|
|
10
10
|
threshold = rand(1000)
|
|
11
11
|
result = set.up_to(threshold)
|
|
@@ -20,7 +20,7 @@ describe Immutable::SortedSet do
|
|
|
20
20
|
context "when called with a block" do
|
|
21
21
|
it "yields all the items equal to or less than than the argument" do
|
|
22
22
|
100.times do
|
|
23
|
-
items = rand(100).times.collect { rand(1000) }
|
|
23
|
+
items = rand(100).times.collect { rand(1000) }.uniq
|
|
24
24
|
set = SS.new(items)
|
|
25
25
|
threshold = rand(1000)
|
|
26
26
|
result = []
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Immutable::SortedSet do
|
|
4
|
+
# Utility method used for filtering out duplicate objects, with equality
|
|
5
|
+
# determined by comparator
|
|
6
|
+
describe ".uniq_by_comparator!" do
|
|
7
|
+
it "can handle empty arrays" do
|
|
8
|
+
array = []
|
|
9
|
+
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
|
|
10
|
+
expect(array).to be_empty
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "can handle arrays with 1 element" do
|
|
14
|
+
array = [1]
|
|
15
|
+
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
|
|
16
|
+
expect(array).to eq([1])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "can handle arrays with 2 elements and no dupes" do
|
|
20
|
+
array = [1, 2]
|
|
21
|
+
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
|
|
22
|
+
expect(array).to eq([1, 2])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "can handle arrays with 2 elements and dupes" do
|
|
26
|
+
array = [1, 1]
|
|
27
|
+
SS.uniq_by_comparator!(array, ->(x,y) { x <=> y })
|
|
28
|
+
expect(array).to eq([1])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "can handle arrays with lots of elements" do
|
|
32
|
+
100.times do
|
|
33
|
+
array1 = rand(100).times.collect { rand(100) }.sort
|
|
34
|
+
array2 = array1.dup.uniq
|
|
35
|
+
SS.uniq_by_comparator!(array1, ->(x,y) { x <=> y })
|
|
36
|
+
expect(array1).to eq(array2)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "works with funny comparators" do
|
|
41
|
+
# let's work in modulo arithmetic
|
|
42
|
+
comparator = ->(x,y) { (x % 7) <=> (y % 7) }
|
|
43
|
+
array = [21, 1, 8, 1, 9, 10, 3, 5, 6, 20] # this is "sorted" (modulo 7)
|
|
44
|
+
SS.uniq_by_comparator!(array, comparator)
|
|
45
|
+
expect(array).to eq([21, 1, 9, 10, 5, 6])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: immutable-ruby
|
|
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
|
- Alex Dowad
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2018-05-12 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: concurrent-ruby
|
|
@@ -408,6 +408,7 @@ files:
|
|
|
408
408
|
- spec/lib/immutable/sorted_set/to_set_spec.rb
|
|
409
409
|
- spec/lib/immutable/sorted_set/union_spec.rb
|
|
410
410
|
- spec/lib/immutable/sorted_set/up_to_spec.rb
|
|
411
|
+
- spec/lib/immutable/sorted_set/util_spec.rb
|
|
411
412
|
- spec/lib/immutable/sorted_set/values_at_spec.rb
|
|
412
413
|
- spec/lib/immutable/vector/add_spec.rb
|
|
413
414
|
- spec/lib/immutable/vector/any_spec.rb
|
|
@@ -787,6 +788,7 @@ test_files:
|
|
|
787
788
|
- spec/lib/immutable/sorted_set/group_by_spec.rb
|
|
788
789
|
- spec/lib/immutable/sorted_set/between_spec.rb
|
|
789
790
|
- spec/lib/immutable/sorted_set/sample_spec.rb
|
|
791
|
+
- spec/lib/immutable/sorted_set/util_spec.rb
|
|
790
792
|
- spec/lib/immutable/sorted_set/values_at_spec.rb
|
|
791
793
|
- spec/lib/immutable/sorted_set/marshal_spec.rb
|
|
792
794
|
- spec/lib/immutable/sorted_set/intersect_spec.rb
|