sorted_containers 0.0.1 → 0.1.1

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.
@@ -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