algorithms 0.0.1 → 0.1.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.
- data/History.txt +139 -2
- data/Manifest +31 -8
- data/README +90 -0
- data/Rakefile +22 -9
- data/algorithms.gemspec +28 -101
- data/benchmark.rb +29 -27
- data/benchmarks/rbench.rb +16 -0
- data/benchmarks/rbench/column.rb +26 -0
- data/benchmarks/rbench/group.rb +43 -0
- data/benchmarks/rbench/report.rb +53 -0
- data/benchmarks/rbench/runner.rb +109 -0
- data/benchmarks/rbench/summary.rb +51 -0
- data/benchmarks/sorts.rb +33 -0
- data/ext/containers/bst/bst.c +205 -0
- data/ext/containers/{priority_queue → bst}/extconf.rb +1 -1
- data/ext/containers/deque/deque.c +233 -0
- data/ext/containers/deque/extconf.rb +4 -0
- data/ext/containers/tree_map/extconf.rb +1 -1
- data/ext/containers/tree_map/rbtree.c +73 -25
- data/lib/algorithms.rb +65 -6
- data/lib/algorithms/search.rb +84 -0
- data/lib/algorithms/sort.rb +238 -0
- data/lib/containers/deque.rb +176 -0
- data/lib/containers/heap.rb +451 -111
- data/lib/containers/kd_tree.rb +87 -0
- data/lib/containers/priority_queue.rb +107 -508
- data/lib/containers/queue.rb +62 -23
- data/lib/containers/rb_tree_map.rb +398 -0
- data/lib/containers/splay_tree_map.rb +274 -0
- data/lib/containers/stack.rb +59 -21
- data/lib/containers/suffix_array.rb +68 -0
- data/lib/containers/trie.rb +182 -0
- data/lib/graphs/graph.rb +25 -0
- data/spec/bst_spec.rb +31 -0
- data/spec/deque_spec.rb +108 -0
- data/spec/heap_spec.rb +111 -66
- data/spec/kd_tree_spec.rb +89 -0
- data/spec/priority_queue_spec.rb +71 -27
- data/spec/queue_spec.rb +53 -45
- data/spec/rb_tree_map_spec.rb +123 -0
- data/spec/search_spec.rb +28 -0
- data/spec/sort_spec.rb +28 -0
- data/spec/splay_tree_map_spec.rb +102 -0
- data/spec/stack_spec.rb +56 -49
- data/spec/suffix_array_spec.rb +40 -0
- data/spec/trie_spec.rb +59 -0
- metadata +54 -32
- data/README.txt +0 -58
- data/ext/containers/priority_queue/priority_queue.c +0 -948
- data/ext/containers/tree_map/Rakefile +0 -4
- data/lib/containers/hash.rb +0 -0
- data/lib/containers/tree_map.rb +0 -265
- data/spec/priority_queue_test.rb +0 -371
- data/spec/tree_map_spec.rb +0 -99
data/lib/graphs/graph.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Graph
|
2
|
+
def initialize(string=nil, &block)
|
3
|
+
p block if block
|
4
|
+
@nodes = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def -(other)
|
8
|
+
@nodes << other
|
9
|
+
end
|
10
|
+
|
11
|
+
def >(other)
|
12
|
+
@nodes << other
|
13
|
+
end
|
14
|
+
end
|
15
|
+
a = Graph.new
|
16
|
+
b = []
|
17
|
+
d = []
|
18
|
+
|
19
|
+
a - b
|
20
|
+
a > d
|
21
|
+
|
22
|
+
Graph.new do
|
23
|
+
d - c
|
24
|
+
g - s
|
25
|
+
end
|
data/spec/bst_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
2
|
+
require "algorithms"
|
3
|
+
|
4
|
+
begin
|
5
|
+
Containers::CBst
|
6
|
+
describe "binary search tree" do
|
7
|
+
it "should let user insert new elements with key" do
|
8
|
+
@bst = Containers::CBst.new
|
9
|
+
100.times { |x| @bst.insert(x, "hello : #{x}") }
|
10
|
+
@bst.size.should eql(100)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should allow users to delete elements" do
|
14
|
+
@bst = Containers::CBst.new
|
15
|
+
@bst.insert(10, "hello world")
|
16
|
+
@bst.insert(11, "hello world")
|
17
|
+
@bst.delete(11)
|
18
|
+
@bst.size.should eql(1)
|
19
|
+
@bst.delete(10)
|
20
|
+
@bst.size.should eql(0)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should throw exception on invalid key delete" do
|
24
|
+
@bst = Containers::CBst.new
|
25
|
+
@bst.insert(10,"Hello world")
|
26
|
+
lambda { @bst.delete(20) }.should raise_error(ArgumentError)
|
27
|
+
@bst.size.should eql(1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue Exception
|
31
|
+
end
|
data/spec/deque_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
2
|
+
require 'algorithms'
|
3
|
+
|
4
|
+
describe "(empty deque)", :shared => true do
|
5
|
+
it "should return nil when popping objects" do
|
6
|
+
@deque.pop_front.should be_nil
|
7
|
+
@deque.pop_back.should be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return a size of 1 when sent #push_front" do
|
11
|
+
@deque.push_front(1)
|
12
|
+
@deque.size.should eql(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return a size of 1 when sent #push_back" do
|
16
|
+
@deque.push_back(1)
|
17
|
+
@deque.size.should eql(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return nil when sent #front and #back" do
|
21
|
+
@deque.front.should be_nil
|
22
|
+
@deque.back.should be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be empty" do
|
26
|
+
@deque.should be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise ArgumentError if passed more than one argument" do
|
30
|
+
lambda { @deque.class.send("new", Time.now, []) }.should raise_error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "(non-empty deque)", :shared => true do
|
35
|
+
before(:each) do
|
36
|
+
@deque.push_back(10)
|
37
|
+
@deque.push_back("10")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return last pushed object with pop_back" do
|
41
|
+
@deque.pop_back.should eql("10")
|
42
|
+
@deque.pop_back.should eql(10)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return first pushed object with pop_front" do
|
46
|
+
@deque.pop_front.should eql(10)
|
47
|
+
@deque.pop_front.should eql("10")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return a size greater than 0" do
|
51
|
+
@deque.size.should eql(2)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not be empty" do
|
55
|
+
@deque.should_not be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should iterate in LIFO order with #each_backward" do
|
59
|
+
arr = []
|
60
|
+
@deque.each_backward { |obj| arr << obj }
|
61
|
+
arr.should eql(["10", 10])
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should iterate in FIFO order with #each_forward" do
|
65
|
+
arr = []
|
66
|
+
@deque.each_forward { |obj| arr << obj }
|
67
|
+
arr.should eql([10, "10"])
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return nil after everything's popped" do
|
71
|
+
@deque.pop_back
|
72
|
+
@deque.pop_back
|
73
|
+
@deque.pop_back.should be_nil
|
74
|
+
@deque.front.should be_nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "empty rubydeque" do
|
79
|
+
before(:each) do
|
80
|
+
@deque = Containers::RubyDeque.new
|
81
|
+
end
|
82
|
+
it_should_behave_like "(empty deque)"
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "full rubydeque" do
|
86
|
+
before(:each) do
|
87
|
+
@deque = Containers::RubyDeque.new
|
88
|
+
end
|
89
|
+
it_should_behave_like "(non-empty deque)"
|
90
|
+
end
|
91
|
+
|
92
|
+
begin
|
93
|
+
Containers::CDeque
|
94
|
+
describe "empty cdeque" do
|
95
|
+
before(:each) do
|
96
|
+
@deque = Containers::CDeque.new
|
97
|
+
end
|
98
|
+
it_should_behave_like "(empty deque)"
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "full cdeque" do
|
102
|
+
before(:each) do
|
103
|
+
@deque = Containers::CDeque.new
|
104
|
+
end
|
105
|
+
it_should_behave_like "(non-empty deque)"
|
106
|
+
end
|
107
|
+
rescue Exception
|
108
|
+
end
|
data/spec/heap_spec.rb
CHANGED
@@ -1,74 +1,119 @@
|
|
1
|
-
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
2
|
+
require 'algorithms'
|
2
3
|
|
3
|
-
describe
|
4
|
+
describe "empty heap" do
|
4
5
|
before(:each) do
|
5
6
|
@heap = Containers::MaxHeap.new
|
6
7
|
end
|
7
|
-
|
8
|
-
describe "(empty)" do
|
9
|
-
|
10
|
-
it "should return nil when getting the maximum" do
|
11
|
-
@heap.get_max!.should eql(nil)
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should let you insert and remove one item" do
|
15
|
-
@heap.size.should eql(0)
|
16
|
-
|
17
|
-
@heap.insert(1)
|
18
|
-
@heap.size.should eql(1)
|
19
|
-
|
20
|
-
@heap.get_max!.should eql(1)
|
21
|
-
@heap.size.should eql(0)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should let you initialize with an array" do
|
25
|
-
@heap = Containers::MaxHeap.new([1,2,3])
|
26
|
-
@heap.size.should eql(3)
|
27
|
-
end
|
28
8
|
|
9
|
+
it "should not let you merge with non-heaps" do
|
10
|
+
lambda { @heap.merge!(nil) }.should raise_error
|
11
|
+
lambda { @heap.merge!([]) }.should raise_error
|
29
12
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
13
|
+
|
14
|
+
it "should return nil when getting the maximum" do
|
15
|
+
@heap.max!.should be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should let you insert and remove one item" do
|
19
|
+
@heap.size.should eql(0)
|
20
|
+
|
21
|
+
@heap.push(1)
|
22
|
+
@heap.size.should eql(1)
|
23
|
+
|
24
|
+
@heap.max!.should eql(1)
|
25
|
+
@heap.size.should eql(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should let you initialize with an array" do
|
29
|
+
@heap = Containers::MaxHeap.new([1,2,3])
|
30
|
+
@heap.size.should eql(3)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "non-empty heap" do
|
36
|
+
before(:each) do
|
37
|
+
@random_array = []
|
38
|
+
@num_items = 100
|
39
|
+
@num_items.times { |x| @random_array << rand(@num_items) }
|
40
|
+
@heap = Containers::MaxHeap.new(@random_array)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should display the correct size" do
|
44
|
+
@heap.size.should eql(@num_items)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should delete random keys" do
|
48
|
+
@heap.delete(@random_array[0]).should eql(@random_array[0])
|
49
|
+
@heap.delete(@random_array[1]).should eql(@random_array[1])
|
50
|
+
ordered = []
|
51
|
+
ordered << @heap.max! until @heap.empty?
|
52
|
+
ordered.should eql( @random_array[2..-1].sort.reverse )
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should delete all keys" do
|
56
|
+
ordered = []
|
57
|
+
@random_array.size.times do |t|
|
58
|
+
ordered << @heap.delete(@random_array[t])
|
70
59
|
end
|
71
|
-
|
60
|
+
@heap.should be_empty
|
61
|
+
ordered.should eql( @random_array )
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be in max->min order" do
|
65
|
+
ordered = []
|
66
|
+
ordered << @heap.max! until @heap.empty?
|
67
|
+
|
68
|
+
ordered.should eql(@random_array.sort.reverse)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should change certain keys" do
|
72
|
+
numbers = [1,2,3,4,5,6,7,8,9,10,100,101]
|
73
|
+
heap = Containers::MinHeap.new(numbers)
|
74
|
+
heap.change_key(101, 50)
|
75
|
+
heap.pop
|
76
|
+
heap.pop
|
77
|
+
heap.change_key(8, 0)
|
78
|
+
ordered = []
|
79
|
+
ordered << heap.min! until heap.empty?
|
80
|
+
ordered.should eql( [8,3,4,5,6,7,9,10,101,100] )
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should not delete keys it doesn't have" do
|
84
|
+
@heap.delete(:nonexisting).should be_nil
|
85
|
+
@heap.size.should eql(@num_items)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should delete certain keys" do
|
89
|
+
numbers = [1,2,3,4,5,6,7,8,9,10,100,101]
|
90
|
+
heap = Containers::MinHeap.new(numbers)
|
91
|
+
heap.delete(5)
|
92
|
+
heap.pop
|
93
|
+
heap.pop
|
94
|
+
heap.delete(100)
|
95
|
+
ordered = []
|
96
|
+
ordered << heap.min! until heap.empty?
|
97
|
+
ordered.should eql( [3,4,6,7,8,9,10,101] )
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should let you merge with another heap" do
|
101
|
+
numbers = [1,2,3,4,5,6,7,8]
|
102
|
+
otherheap = Containers::MaxHeap.new(numbers)
|
103
|
+
otherheap.size.should eql(8)
|
104
|
+
@heap.merge!(otherheap)
|
105
|
+
|
106
|
+
ordered = []
|
107
|
+
ordered << @heap.max! until @heap.empty?
|
108
|
+
|
109
|
+
ordered.should eql( (@random_array + numbers).sort.reverse)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "min-heap should be in min->max order" do
|
113
|
+
@heap = Containers::MinHeap.new(@random_array)
|
114
|
+
ordered = []
|
115
|
+
ordered << @heap.min! until @heap.empty?
|
116
|
+
|
117
|
+
ordered.should eql(@random_array.sort)
|
72
118
|
end
|
73
|
-
|
74
|
-
end
|
119
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
2
|
+
require 'algorithms'
|
3
|
+
|
4
|
+
#!/usr/bin/ruby
|
5
|
+
# Small world puzzle
|
6
|
+
# Kanwei Li, 2009
|
7
|
+
|
8
|
+
# Make sure input file exists and read from it
|
9
|
+
filename = ARGV[0]
|
10
|
+
unless filename && File.exist?(filename)
|
11
|
+
puts "error: must specify a valid input file"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
input = File.open(filename)
|
15
|
+
|
16
|
+
$points = [] # Store array of points as a global so we don't have to pass it around
|
17
|
+
|
18
|
+
# Populate points array
|
19
|
+
# while line = input.gets do
|
20
|
+
# break if line.empty?
|
21
|
+
# n, x, y = line.split(/\s+/)
|
22
|
+
# $points << [n.to_i, [x.to_f, y.to_f]]
|
23
|
+
# end
|
24
|
+
|
25
|
+
tree = Containers::KDTree.new($points)
|
26
|
+
p tree
|
27
|
+
|
28
|
+
$points.sort { |a, b| a[0] <=> b[0] }.each do |point|
|
29
|
+
nearest_4 = tree.find_nearest(point[1], 4)
|
30
|
+
puts "#{point[0]} #{nearest_4[1..-1].collect{ |n| n[1] }.join(',')}\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# describe "empty trie" do
|
35
|
+
# before(:each) do
|
36
|
+
# @trie = Containers::Trie.new
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# it "should not get or has_key?" do
|
40
|
+
# @trie.get("anything").should be_nil
|
41
|
+
# @trie.has_key?("anything").should be_false
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# it "should not have longest_prefix or match wildcards" do
|
45
|
+
# @trie.wildcard("an*thing").should eql([])
|
46
|
+
# @trie.longest_prefix("an*thing").should eql("")
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# describe "non-empty trie" do
|
51
|
+
# before(:each) do
|
52
|
+
# @trie = Containers::Trie.new
|
53
|
+
# @trie.push("Hello", "World")
|
54
|
+
# @trie.push("Hilly", "World")
|
55
|
+
# @trie.push("Hello, brother", "World")
|
56
|
+
# @trie.push("Hello, bob", "World")
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# it "should has_key? keys it has" do
|
60
|
+
# @trie.has_key?("Hello").should be_true
|
61
|
+
# @trie.has_key?("Hello, brother").should be_true
|
62
|
+
# @trie.has_key?("Hello, bob").should be_true
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# it "should not has_key? keys it doesn't have" do
|
66
|
+
# @trie.has_key?("Nope").should be_false
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# it "should get values" do
|
70
|
+
# @trie.get("Hello").should eql("World")
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# it "should overwrite values" do
|
74
|
+
# @trie.push("Hello", "John")
|
75
|
+
# @trie.get("Hello").should eql("John")
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# it "should return longest prefix" do
|
79
|
+
# @trie.longest_prefix("Hello, brandon").should eql("Hello")
|
80
|
+
# @trie.longest_prefix("Hel").should eql("")
|
81
|
+
# @trie.longest_prefix("Hello").should eql("Hello")
|
82
|
+
# @trie.longest_prefix("Hello, bob").should eql("Hello, bob")
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# it "should match wildcards" do
|
86
|
+
# @trie.wildcard("H*ll.").should eql(["Hello", "Hilly"])
|
87
|
+
# @trie.wildcard("Hel").should eql([])
|
88
|
+
# end
|
89
|
+
# end
|
data/spec/priority_queue_spec.rb
CHANGED
@@ -1,31 +1,75 @@
|
|
1
|
-
|
1
|
+
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
2
|
+
require 'algorithms'
|
2
3
|
|
3
|
-
describe
|
4
|
+
describe "empty priority queue" do
|
4
5
|
before(:each) do
|
5
|
-
@q = Containers::
|
6
|
-
end
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@q.
|
27
|
-
@q.
|
6
|
+
@q = Containers::PriorityQueue.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return 0 for size and be empty" do
|
10
|
+
@q.size.should eql(0)
|
11
|
+
@q.should be_empty
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not return anything" do
|
15
|
+
@q.next.should be_nil
|
16
|
+
@q.pop.should be_nil
|
17
|
+
@q.delete(1).should be_nil
|
18
|
+
@q.has_priority?(1).should be_false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should give the correct size when adding items" do
|
22
|
+
20.times do |i|
|
23
|
+
@q.size.should eql(i)
|
24
|
+
@q.push(i, i)
|
25
|
+
end
|
26
|
+
10.times do |i|
|
27
|
+
@q.size.should eql(20-i)
|
28
|
+
@q.pop
|
29
|
+
end
|
30
|
+
10.times do |i|
|
31
|
+
@q.size.should eql(i+10)
|
32
|
+
@q.push(i, i)
|
33
|
+
end
|
34
|
+
@q.delete(5)
|
35
|
+
@q.size.should eql(19)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "non-empty priority queue" do
|
40
|
+
before(:each) do
|
41
|
+
@q = Containers::PriorityQueue.new
|
42
|
+
@q.push("Alaska", 50)
|
43
|
+
@q.push("Delaware", 30)
|
44
|
+
@q.push("Georgia", 35)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should next/pop the highest priority" do
|
48
|
+
@q.next.should eql("Alaska")
|
49
|
+
@q.size.should eql(3)
|
50
|
+
@q.pop.should eql("Alaska")
|
51
|
+
@q.size.should eql(2)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not be empty" do
|
55
|
+
@q.should_not be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should has_priority? priorities it has" do
|
59
|
+
@q.has_priority?(50).should be_true
|
60
|
+
@q.has_priority?(10).should be_false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return nil after popping everything" do
|
64
|
+
3.times do
|
65
|
+
@q.pop
|
28
66
|
end
|
67
|
+
@q.pop.should be_nil
|
29
68
|
end
|
30
|
-
|
31
|
-
|
69
|
+
|
70
|
+
it "should delete things it has and not things it doesn't" do
|
71
|
+
@q.delete(50).should eql("Alaska")
|
72
|
+
@q.delete(10).should eql(nil)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|