sorted_containers 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "sorted_array"
4
+
5
+ # The SortedContainers module provides data structures for sorted collections.
6
+ module SortedContainers
7
+ # The SortedHash class represents a sorted hash.
8
+ class SortedHash
9
+ include Enumerable
10
+
11
+ # Initializes a new instance of the SortedHash class.
12
+ #
13
+ # @param load_factor [Integer] The load factor for the SortedHash.
14
+ def initialize(hash = {}, load_factor: SortedArray::DEFAULT_LOAD_FACTOR)
15
+ @hash = hash
16
+ @sorted_array = SortedArray.new(hash.keys, load_factor: load_factor)
17
+ end
18
+
19
+ # Retrieves the value associated with the specified key.
20
+ #
21
+ # @param key [Object] The key to retrieve the value for.
22
+ # @return [Object] The value associated with the key, or nil if the key is not found.
23
+ def [](key)
24
+ @hash[key]
25
+ end
26
+
27
+ # Associates the specified value with the specified key.
28
+ # If the key already exists, the previous value will be replaced.
29
+ #
30
+ # @param key [Object] The key to associate the value with.
31
+ # @param value [Object] The value to be associated with the key.
32
+ # @return [Object] The value that was associated with the key.
33
+ def []=(key, value)
34
+ @sorted_array.delete(key) if @hash.key?(key)
35
+ @sorted_array.add(key)
36
+ @hash[key] = value
37
+ end
38
+
39
+ # Returns a string representation of the SortedHash.
40
+ #
41
+ # @return [String] A string representation of the SortedHash.
42
+ def to_s
43
+ "SortedHash({#{keys.map { |key| "#{key}: #{self[key]}" }.join(", ")}})"
44
+ end
45
+
46
+ # Deletes the key-value pair associated with the specified key.
47
+ #
48
+ # @param key [Object] The key to delete.
49
+ # @return [void]
50
+ def delete(key)
51
+ return unless @hash.key?(key)
52
+
53
+ @hash.delete(key)
54
+ @sorted_array.delete(key)
55
+ end
56
+
57
+ # Deletes the key-value pair at the specified index and returns it as a two-element array.
58
+ #
59
+ # @param index [Integer] The index of the key-value pair to delete.
60
+ # @return [Array] A two-element array containing the key and value of the deleted key-value pair.
61
+ def delete_at(index)
62
+ return nil if index.abs >= @sorted_array.size
63
+
64
+ key = @sorted_array.delete_at(index)
65
+ value = @hash.delete(key)
66
+ [key, value]
67
+ end
68
+
69
+ # Retrieves the first key-value pair from the SortedHash as a two-element array.
70
+ #
71
+ # @return [Array] A two-element array containing the key and value of the first key-value pair.
72
+ def first
73
+ return nil if @sorted_array.empty?
74
+
75
+ key = @sorted_array.first
76
+ [key, @hash[key]]
77
+ end
78
+
79
+ # Removes the first key-value pair from the SortedHash and returns it as a two-element array.
80
+ #
81
+ # @return [Array] A two-element array containing the key and value of the first key-value pair.
82
+ def last
83
+ return nil if @sorted_array.empty?
84
+
85
+ key = @sorted_array.last
86
+ [key, @hash[key]]
87
+ end
88
+
89
+ # Removes the last key-value pair from the SortedHash and returns it as a two-element array.
90
+ #
91
+ # @return [Array] A two-element array containing the key and value of the last key-value pair.
92
+ def pop
93
+ return nil if @sorted_array.empty?
94
+
95
+ key = @sorted_array.pop
96
+ value = @hash.delete(key)
97
+ [key, value]
98
+ end
99
+
100
+ # Removes the first key-value pair from the SortedHash and returns it as a two-element array.
101
+ #
102
+ # @return [Array] A two-element array containing the key and value of the first key-value pair.
103
+ def shift
104
+ return nil if @sorted_array.empty?
105
+
106
+ key = @sorted_array.shift
107
+ value = @hash.delete(key)
108
+ [key, value]
109
+ end
110
+
111
+ # Returns the number of key-value pairs in the SortedHash.
112
+ #
113
+ # @return [Integer] The number of key-value pairs.
114
+ def bisect_left(key)
115
+ @sorted_array.bisect_left(key)
116
+ end
117
+
118
+ # Returns the number of key-value pairs in the SortedHash.
119
+ #
120
+ # @return [Integer] The number of key-value pairs.
121
+ def bisect_right(key)
122
+ @sorted_array.bisect_right(key)
123
+ end
124
+
125
+ # Returns an array of all the keys in the SortedHash.
126
+ #
127
+ # @return [Array] An array of all the keys.
128
+ def keys
129
+ @sorted_array.to_a
130
+ end
131
+
132
+ # Returns an array of all the values in the SortedHash.
133
+ #
134
+ # @return [Array] An array of all the values.
135
+ def values
136
+ @sorted_array.to_a.map { |key| @hash[key] }
137
+ end
138
+
139
+ # Iterates over each key-value pair in the SortedHash.
140
+ #
141
+ # @yield [key, value] The block to be executed for each key-value pair.
142
+ # @yieldparam key [Object] The key of the current key-value pair.
143
+ # @yieldparam value [Object] The value of the current key-value pair.
144
+ # @return [void]
145
+ def each(&block)
146
+ @sorted_array.each do |key|
147
+ value = @hash[key]
148
+ block.call(key, value)
149
+ end
150
+ end
151
+ end
152
+ end
@@ -1,16 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
- require_relative "sorted_list"
4
+ require_relative "sorted_array"
5
5
 
6
6
  # A module that provides sorted container data structures.
7
7
  module SortedContainers
8
8
  # The SortedSet class is a sorted set implementation.
9
9
  class SortedSet
10
+ include Enumerable
11
+
10
12
  # Initializes a new instance of the SortedSet class.
11
- def initialize
12
- @set = Set.new
13
- @list = SortedContainers::SortedList.new
13
+ #
14
+ # @param iterable [Array] The initial elements of the sorted set.
15
+ # @param load_factor [Integer] The load factor for the sorted set.
16
+ def initialize(iterable = [], load_factor: SortedArray::DEFAULT_LOAD_FACTOR)
17
+ @set = Set.new(iterable)
18
+ @list = SortedContainers::SortedArray.new(@set.to_a, load_factor: load_factor)
14
19
  end
15
20
 
16
21
  # Adds an item to the sorted set.
@@ -22,12 +27,34 @@ module SortedContainers
22
27
  @set.add(item)
23
28
  @list.add(item)
24
29
  end
30
+ alias << add
25
31
 
26
- # Adds an item to the sorted set using the `<<` operator.
32
+ # Retrieves the item at the specified index.
27
33
  #
28
- # @param item [Object] The item to be added.
29
- def <<(item)
30
- add(item)
34
+ # @param index [Integer] The index of the item to retrieve.
35
+ def [](index)
36
+ @list[index]
37
+ end
38
+
39
+ # Returns a string representation of the sorted set.
40
+ #
41
+ # @return [String] A string representation of the sorted set.
42
+ def to_s
43
+ "SortedSet(#{to_a.join(", ")})"
44
+ end
45
+
46
+ # Retrieves the first item in the sorted set.
47
+ #
48
+ # @return [Object] The first item.
49
+ def first
50
+ @list.first
51
+ end
52
+
53
+ # Retrieves the last item in the sorted set.
54
+ #
55
+ # @return [Object] The last item.
56
+ def last
57
+ @list.last
31
58
  end
32
59
 
33
60
  # Removes an item from the sorted set.
@@ -37,7 +64,18 @@ module SortedContainers
37
64
  return unless @set.include?(item)
38
65
 
39
66
  @set.delete(item)
40
- @list.remove(item)
67
+ @list.delete(item)
68
+ end
69
+
70
+ # Removes the item at the specified index.
71
+ #
72
+ # @param index [Integer] The index of the item to remove.
73
+ def delete_at(index)
74
+ return if index.abs >= @list.size
75
+
76
+ item = @list.delete_at(index)
77
+ @set.delete(item)
78
+ item
41
79
  end
42
80
 
43
81
  # Returns the number of items in the sorted set.
@@ -55,6 +93,41 @@ module SortedContainers
55
93
  @set.include?(item)
56
94
  end
57
95
 
96
+ # Returns an index to insert `value` in the sorted list.
97
+ #
98
+ # If the `value` is already present, the insertion point will be before
99
+ # (to the left of) any existing values.
100
+ #
101
+ # Runtime complexity: `O(log(n))` -- approximate.
102
+ #
103
+ # @see SortedArray#bisect_left
104
+ # @param value [Object] The value to insert.
105
+ # @return [Integer] The index to insert the value.
106
+ def bisect_left(value)
107
+ @list.bisect_left(value)
108
+ end
109
+
110
+ # Returns an index to insert `value` in the sorted list.
111
+ #
112
+ # If the `value` is already present, the insertion point will be after
113
+ # (to the right of) any existing values.
114
+ #
115
+ # Runtime complexity: `O(log(n))` -- approximate.
116
+ #
117
+ # @see SortedArray#bisect_right
118
+ # @param value [Object] The value to insert.
119
+ # @return [Integer] The index to insert the value.
120
+ def bisect_right(value)
121
+ @list.bisect_right(value)
122
+ end
123
+
124
+ # Returns the items in the sorted set as an array.
125
+ #
126
+ # @return [Array] The items in the sorted set.
127
+ def to_a
128
+ @list.to_a
129
+ end
130
+
58
131
  # Iterates over each item in the sorted set.
59
132
  #
60
133
  # @yield [item] Gives each item to the block.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SortedContainers
4
- VERSION = "0.0.1"
4
+ VERSION = "0.1.1"
5
5
  end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "sorted_containers/version"
4
- require_relative "sorted_containers/sorted_list"
4
+ require_relative "sorted_containers/sorted_array"
5
5
  require_relative "sorted_containers/sorted_set"
6
-
7
- module SortedContainers
8
- class Error < StandardError; end
9
- end
6
+ require_relative "sorted_containers/sorted_hash"
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorted_containers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garrison Jensen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-16 00:00:00.000000000 Z
11
+ date: 2024-04-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A collection of sorted containers including SortedList, SortedDict, and
14
- SortedSet.
13
+ description: A collection of sorted containers including SortedArray, SortedDict,
14
+ and SortedSet.
15
15
  email:
16
16
  - garrison.jensen@gmail.com
17
17
  executables: []
@@ -26,7 +26,8 @@ files:
26
26
  - README.md
27
27
  - Rakefile
28
28
  - lib/sorted_containers.rb
29
- - lib/sorted_containers/sorted_list.rb
29
+ - lib/sorted_containers/sorted_array.rb
30
+ - lib/sorted_containers/sorted_hash.rb
30
31
  - lib/sorted_containers/sorted_set.rb
31
32
  - lib/sorted_containers/version.rb
32
33
  - sig/sorted_containers.rbs
@@ -54,8 +55,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
55
  - !ruby/object:Gem::Version
55
56
  version: '0'
56
57
  requirements: []
57
- rubygems_version: 3.5.7
58
+ rubygems_version: 3.5.9
58
59
  signing_key:
59
60
  specification_version: 4
60
- summary: A collection of sorted containers including SortedList, SortedDict, and SortedSet.
61
+ summary: A collection of sorted containers including SortedArray, SortedDict, and
62
+ SortedSet.
61
63
  test_files: []
@@ -1,174 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # The SortedContainers module provides data structures for sorted collections.
4
- module SortedContainers
5
- class Error < StandardError; end
6
-
7
- # The SortedList class is a sorted list implementation.
8
- class SortedList
9
- DEFAULT_LOAD_FACTOR = 1000
10
-
11
- attr_reader :size
12
-
13
- # Initializes a new SortedList object.
14
- #
15
- # @param iterable [Enumerable] An optional iterable object to initialize the list with.
16
- def initialize(iterable = [])
17
- @lists = []
18
- @maxes = []
19
- @load_factor = DEFAULT_LOAD_FACTOR
20
- @size = 0
21
- update(iterable)
22
- end
23
-
24
- # Adds a value to the sorted list.
25
- #
26
- # @param value [Object] The value to add.
27
- def add(value)
28
- i = bisect_right(@maxes, value)
29
- if i == @maxes.size
30
- @lists.push([value])
31
- @maxes.push(value)
32
- else
33
- idx = bisect_right(@lists[i], value)
34
- @lists[i].insert(idx, value)
35
- @maxes[i] = @lists[i].last
36
- expand(i) if @lists[i].size > (@load_factor * 2)
37
- end
38
- @size += 1
39
- end
40
-
41
- # Adds a value to the sorted list using the << operator.
42
- #
43
- # @param value [Object] The value to add.
44
- def <<(value)
45
- add(value)
46
- end
47
-
48
- def remove(value)
49
- i = bisect_left(@maxes, value)
50
- raise "Value not found: #{value}" if i == @maxes.size
51
-
52
- idx = bisect_left(@lists[i], value)
53
- raise "Value not found: #{value}" unless @lists[i][idx] == value
54
-
55
- internal_delete(i, idx)
56
- end
57
-
58
- # Retrieves the value at the specified index.
59
- #
60
- # @param index [Integer] The index of the value to retrieve.
61
- # @return [Object] The value at the specified index.
62
- def [](index)
63
- raise "Index out of range" if index.negative? || index >= @size
64
-
65
- @lists.each do |sublist|
66
- return sublist[index] if index < sublist.size
67
-
68
- index -= sublist.size
69
- end
70
- end
71
-
72
- # Deletes the value at the specified index.
73
- #
74
- # @param index [Integer] The index of the value to delete.
75
- def delete_at(index)
76
- raise "Index out of range" if index.negative? || index >= @size
77
-
78
- deleted = false
79
- @lists.each_with_index do |sublist, sublist_index|
80
- if index < sublist.size
81
- internal_delete(sublist_index, index)
82
- deleted = true
83
- break
84
- else
85
- index -= sublist.size
86
- end
87
- end
88
-
89
- raise "Index out of range" unless deleted
90
- end
91
-
92
- # Clears the sorted list, removing all values.
93
- def clear
94
- @lists.clear
95
- @maxes.clear
96
- @size = 0
97
- end
98
-
99
- # Checks if the sorted list contains a value.
100
- #
101
- # @param value [Object] The value to check.
102
- # @return [Boolean] True if the value is found, false otherwise.
103
- def contains(value)
104
- i = bisect_left(@maxes, value)
105
- return false if i == @maxes.size
106
-
107
- sublist = @lists[i]
108
- idx = bisect_left(sublist, value)
109
- idx < sublist.size && sublist[idx] == value
110
- end
111
-
112
- # Converts the sorted list to an array.
113
- #
114
- # @return [Array] An array representation of the sorted list.
115
- def to_a
116
- @lists.flatten
117
- end
118
-
119
- private
120
-
121
- # Performs a left bisect on the array.
122
- #
123
- # @param array [Array] The array to bisect.
124
- # @param value [Object] The value to bisect with.
125
- # @return [Integer] The index where the value should be inserted.
126
- def bisect_left(array, value)
127
- array.bsearch_index { |x| x >= value } || array.size
128
- end
129
-
130
- # Performs a right bisect on the array.
131
- #
132
- # @param array [Array] The array to bisect.
133
- # @param value [Object] The value to bisect with.
134
- # @return [Integer] The index where the value should be inserted.
135
- def bisect_right(array, value)
136
- array.bsearch_index { |x| x > value } || array.size
137
- end
138
-
139
- # Expands a sublist if it exceeds the load factor.
140
- #
141
- # @param sublist_index [Integer] The index of the sublist to expand.
142
- def expand(sublist_index)
143
- sublist = @lists[sublist_index]
144
- return unless sublist.size > (@load_factor * 2)
145
-
146
- half = sublist.slice!(@load_factor, sublist.size - @load_factor)
147
- @lists.insert(sublist_index + 1, half)
148
- @maxes[sublist_index] = @lists[sublist_index].last
149
- @maxes.insert(sublist_index + 1, half.last)
150
- end
151
-
152
- # Deletes a value from a sublist.
153
- #
154
- # @param sublist_index [Integer] The index of the sublist.
155
- # @param idx [Integer] The index of the value to delete.
156
- def internal_delete(sublist_index, idx)
157
- @lists[sublist_index].delete_at(idx)
158
- if @lists[sublist_index].empty?
159
- @lists.delete_at(sublist_index)
160
- @maxes.delete_at(sublist_index)
161
- else
162
- @maxes[sublist_index] = @lists[sublist_index].last
163
- end
164
- @size -= 1
165
- end
166
-
167
- # Updates the sorted list with values from an iterable object.
168
- #
169
- # @param iterable [Enumerable] The iterable object to update the list with.
170
- def update(iterable)
171
- iterable.each { |item| add(item) }
172
- end
173
- end
174
- end