skn_utils 3.3.4 → 3.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/bench_linklists.rb +74 -0
- data/bin/{benchmark.rb → bench_nested_result.rb} +15 -51
- data/lib/skn_utils/lists/circular_linked_list.rb +99 -46
- data/lib/skn_utils/lists/doubly_linked_list.rb +42 -8
- data/lib/skn_utils/lists/link_node.rb +8 -8
- data/lib/skn_utils/lists/linked_list.rb +34 -12
- data/lib/skn_utils/version.rb +1 -1
- data/spec/lib/skn_utils/lists/Circular_linked_list_spec.rb +165 -258
- data/spec/lib/skn_utils/lists/doubly_linked_list_spec.rb +165 -260
- data/spec/lib/skn_utils/lists/linked_list_spec.rb +145 -260
- data/spec/spec_helper.rb +1 -0
- data/spec/support/shared_examples_for_linked_list.rb +156 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84cb7bcd483e3369c94109704c491658263a497d
|
4
|
+
data.tar.gz: 0fefb9e19e864638acfeaa605dd315e12db33a0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66f1414ed28fae1ab9e2701c6d21590e9ea463303964c23de9ffd0f3eabe5df701bc18bb6cceb9c98752d353038d79bbffb97909d1dd447c683eeafc88c9cb12
|
7
|
+
data.tar.gz: 3552bd034096bc4c60f339082af9a22f09bfe57e4c53b589507306e3e190e7598a5b765da62f7ad561fa5270df14652f6272d9d939359c32901cc10802c54abe
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Ref: https://github.com/evanphx/benchmark-ips
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'bundler/setup'
|
8
|
+
require 'skn_utils'
|
9
|
+
require 'ostruct'
|
10
|
+
require 'benchmark/ips'
|
11
|
+
|
12
|
+
class GCSuite
|
13
|
+
def warming(*)
|
14
|
+
run_gc
|
15
|
+
end
|
16
|
+
|
17
|
+
def running(*)
|
18
|
+
run_gc
|
19
|
+
end
|
20
|
+
|
21
|
+
def warmup_stats(*)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_report(*)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def run_gc
|
30
|
+
GC.enable
|
31
|
+
GC.start
|
32
|
+
GC.disable
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
suite = GCSuite.new
|
37
|
+
|
38
|
+
# Warming up --------------------------------------
|
39
|
+
# LinkedList Ops 2.297k i/100ms
|
40
|
+
# Array Ops 34.468k i/100ms
|
41
|
+
# Calculating -------------------------------------
|
42
|
+
# LinkedList Ops 17.015k (±35.2%) i/s - 71.207k in 5.100193s
|
43
|
+
# Array Ops 377.943k (± 7.3%) i/s - 1.896M in 5.048217s
|
44
|
+
#
|
45
|
+
# Comparison:
|
46
|
+
# Array Ops: 377942.7 i/s
|
47
|
+
# LinkedList Ops: 17015.4 i/s - 22.21x slower
|
48
|
+
|
49
|
+
|
50
|
+
Benchmark.ips do |x|
|
51
|
+
x.config(:suite => suite)
|
52
|
+
|
53
|
+
adders = [50, 10, 110, 6, 30, 101, 12, 33, 4]
|
54
|
+
vargs = [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
|
55
|
+
cproc = lambda {|a| a}
|
56
|
+
|
57
|
+
x.report('LinkedList Ops') do
|
58
|
+
ll = SknUtils::Lists::LinkedList.new(*vargs, &cproc)
|
59
|
+
adders.each {|x| ll.insert_after(74, x)}
|
60
|
+
value = ll.sort!
|
61
|
+
ll.first
|
62
|
+
ll.clear
|
63
|
+
end
|
64
|
+
|
65
|
+
x.report('Array Ops') do
|
66
|
+
ary = Array.new(vargs)
|
67
|
+
adders.each {|x| ary.insert(5, x)}
|
68
|
+
value = ary.sort!
|
69
|
+
ary.first
|
70
|
+
ary.clear
|
71
|
+
end
|
72
|
+
|
73
|
+
x.compare!
|
74
|
+
end
|
@@ -35,6 +35,21 @@ end
|
|
35
35
|
|
36
36
|
suite = GCSuite.new
|
37
37
|
|
38
|
+
# Warming up --------------------------------------
|
39
|
+
# regular class 179.755k i/100ms
|
40
|
+
# OpenStruct class 11.367k i/100ms
|
41
|
+
# NestedResult class 9.674k i/100ms
|
42
|
+
# Calculating -------------------------------------
|
43
|
+
# regular class 3.674M (±17.4%) i/s - 17.256M in 5.001576s
|
44
|
+
# OpenStruct class 155.394k (±31.2%) i/s - 670.653k in 5.095404s
|
45
|
+
# NestedResult class 119.896k (±39.0%) i/s - 493.374k in 5.212147s
|
46
|
+
#
|
47
|
+
# Comparison:
|
48
|
+
# regular class: 3673640.5 i/s
|
49
|
+
# OpenStruct class: 155394.0 i/s - 23.64x slower
|
50
|
+
# NestedResult class: 119896.1 i/s - 30.64x slower
|
51
|
+
#
|
52
|
+
|
38
53
|
Benchmark.ips do |x|
|
39
54
|
x.config(:suite => suite)
|
40
55
|
|
@@ -65,54 +80,3 @@ Benchmark.ips do |x|
|
|
65
80
|
|
66
81
|
x.compare!
|
67
82
|
end
|
68
|
-
|
69
|
-
# Warming up --------------------------------------
|
70
|
-
# regular class 179.755k i/100ms
|
71
|
-
# OpenStruct class 11.367k i/100ms
|
72
|
-
# NestedResult class 9.674k i/100ms
|
73
|
-
# Calculating -------------------------------------
|
74
|
-
# regular class 3.674M (±17.4%) i/s - 17.256M in 5.001576s
|
75
|
-
# OpenStruct class 155.394k (±31.2%) i/s - 670.653k in 5.095404s
|
76
|
-
# NestedResult class 119.896k (±39.0%) i/s - 493.374k in 5.212147s
|
77
|
-
#
|
78
|
-
# Comparison:
|
79
|
-
# regular class: 3673640.5 i/s
|
80
|
-
# OpenStruct class: 155394.0 i/s - 23.64x slower
|
81
|
-
# NestedResult class: 119896.1 i/s - 30.64x slower
|
82
|
-
#
|
83
|
-
# Warming up --------------------------------------
|
84
|
-
# LinkedList Ops 2.297k i/100ms
|
85
|
-
# Array Ops 34.468k i/100ms
|
86
|
-
# Calculating -------------------------------------
|
87
|
-
# LinkedList Ops 17.015k (±35.2%) i/s - 71.207k in 5.100193s
|
88
|
-
# Array Ops 377.943k (± 7.3%) i/s - 1.896M in 5.048217s
|
89
|
-
#
|
90
|
-
# Comparison:
|
91
|
-
# Array Ops: 377942.7 i/s
|
92
|
-
# LinkedList Ops: 17015.4 i/s - 22.21x slower
|
93
|
-
|
94
|
-
|
95
|
-
Benchmark.ips do |x|
|
96
|
-
x.config(:suite => suite)
|
97
|
-
|
98
|
-
adders = [50, 10, 110, 6, 30, 101, 12, 33, 4]
|
99
|
-
vargs = [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
|
100
|
-
|
101
|
-
x.report('LinkedList Ops') do
|
102
|
-
ll = SknUtils::Lists::LinkedList.new(*vargs)
|
103
|
-
adders.each {|x| ll.insert_after(74, x)}
|
104
|
-
value = ll.sort!
|
105
|
-
ll.first
|
106
|
-
ll.clear
|
107
|
-
end
|
108
|
-
|
109
|
-
x.report('Array Ops') do
|
110
|
-
ary = Array.new(vargs)
|
111
|
-
adders.each {|x| ary.insert(5, x)}
|
112
|
-
value = ary.sort!
|
113
|
-
ary.first
|
114
|
-
ary.clear
|
115
|
-
end
|
116
|
-
|
117
|
-
x.compare!
|
118
|
-
end
|
@@ -1,3 +1,26 @@
|
|
1
|
+
##
|
2
|
+
# File <SknUtils>/lib/skn_utils/lists/circular_linked_list.rb
|
3
|
+
#
|
4
|
+
# ll = SknUtils::Lists::CircularLinkedList.new(*vargs, &compare_key_proc)
|
5
|
+
# - or -
|
6
|
+
# ll = SknUtils::Lists::CircularLinkedList.new(1,2,3,4,5) {|element| element[:key] }
|
7
|
+
# - or -
|
8
|
+
# ll = SknUtils::Lists::CircularLinkedList.new(
|
9
|
+
# {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
|
10
|
+
# ) {|el| el[:key] }
|
11
|
+
# - or -
|
12
|
+
# cmp_proc = lambda { |el| el[:key] }
|
13
|
+
# vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
|
14
|
+
# ll = SknUtils::Lists::CircularLinkedList.new(*vargs, &cmp_proc)
|
15
|
+
###
|
16
|
+
# value = ll.first
|
17
|
+
# value = ll.at_index(4)
|
18
|
+
# count = ll.insert({key: 'anyValue'})
|
19
|
+
# ...
|
20
|
+
# count = ll.sort! -- defaults to :asc
|
21
|
+
# count = ll.sort!(:desc)
|
22
|
+
# count = ll.sort!() {|a,b| a[:key] <= b[:key] }
|
23
|
+
##
|
1
24
|
|
2
25
|
module SknUtils
|
3
26
|
module Lists
|
@@ -29,7 +52,7 @@ module SknUtils
|
|
29
52
|
# return values and position current to last node accessed
|
30
53
|
# prevent @current from nil assignment
|
31
54
|
def first
|
32
|
-
@current = head if head
|
55
|
+
@current = self.head if self.head
|
33
56
|
@current.value rescue nil
|
34
57
|
end
|
35
58
|
|
@@ -48,7 +71,7 @@ module SknUtils
|
|
48
71
|
end
|
49
72
|
|
50
73
|
def last
|
51
|
-
@current = tail if tail
|
74
|
+
@current = self.tail if self.tail
|
52
75
|
@current.value rescue nil
|
53
76
|
end
|
54
77
|
|
@@ -81,7 +104,7 @@ module SknUtils
|
|
81
104
|
end
|
82
105
|
|
83
106
|
def empty?
|
84
|
-
size == 0
|
107
|
+
self.size == 0
|
85
108
|
end
|
86
109
|
|
87
110
|
#
|
@@ -96,12 +119,12 @@ module SknUtils
|
|
96
119
|
|
97
120
|
# return new size
|
98
121
|
def prepend(value)
|
99
|
-
temp = head.value rescue nil
|
122
|
+
temp = self.head.value rescue nil
|
100
123
|
insert_before(temp, value)
|
101
124
|
end
|
102
125
|
# return new size
|
103
126
|
def append(value)
|
104
|
-
temp = tail.value rescue nil
|
127
|
+
temp = self.tail.value rescue nil
|
105
128
|
insert_after(temp, value)
|
106
129
|
end
|
107
130
|
|
@@ -109,9 +132,19 @@ module SknUtils
|
|
109
132
|
def insert_before(position_value, value)
|
110
133
|
target = find_by_value(position_value)
|
111
134
|
node = LinkNode.new(value, target, :circle_before, &@match_value)
|
112
|
-
@current = node
|
113
|
-
self.
|
114
|
-
|
135
|
+
@current = node
|
136
|
+
if self.size == 0 # only
|
137
|
+
self.head = node
|
138
|
+
self.tail = node
|
139
|
+
elsif self.head == target # new head
|
140
|
+
self.head = node
|
141
|
+
node.prev = self.tail
|
142
|
+
self.tail.next = node
|
143
|
+
elsif self.tail == target
|
144
|
+
self.tail = node
|
145
|
+
node.next = self.head
|
146
|
+
self.head.prev = node
|
147
|
+
end
|
115
148
|
self.size += 1
|
116
149
|
end
|
117
150
|
|
@@ -120,8 +153,18 @@ module SknUtils
|
|
120
153
|
target = find_by_value(position_value)
|
121
154
|
node = LinkNode.new(value, target, :circle_after, &@match_value)
|
122
155
|
@current = node
|
123
|
-
self.
|
124
|
-
|
156
|
+
if self.size == 0 # only
|
157
|
+
self.head = node
|
158
|
+
self.tail = node
|
159
|
+
elsif self.tail == target
|
160
|
+
self.tail = node
|
161
|
+
node.next = self.head
|
162
|
+
self.head.prev = node
|
163
|
+
elsif self.head == target # new head
|
164
|
+
self.head = node
|
165
|
+
node.prev = self.tail
|
166
|
+
self.tail.next = node
|
167
|
+
end
|
125
168
|
self.size += 1
|
126
169
|
end
|
127
170
|
|
@@ -129,25 +172,40 @@ module SknUtils
|
|
129
172
|
def remove(value)
|
130
173
|
target_node = find_by_value(value)
|
131
174
|
if target_node
|
132
|
-
|
133
|
-
|
134
|
-
|
175
|
+
if self.size == 1 # will become zero
|
176
|
+
@current = nil
|
177
|
+
self.head = nil
|
178
|
+
self.tail = nil
|
179
|
+
elsif target_node === self.head # top
|
180
|
+
@current = target_node.next
|
181
|
+
@current.prev = target_node.prev
|
182
|
+
self.tail.next = @current
|
183
|
+
self.head = @current
|
184
|
+
elsif target_node === self.tail # bottom
|
185
|
+
@current = target_node.prev
|
186
|
+
@current.next = target_node.next
|
187
|
+
self.head.prev = @current
|
188
|
+
self.tail = @current
|
189
|
+
else # middle
|
190
|
+
@current = target_node.prev
|
191
|
+
@current.next = target_node.next
|
192
|
+
@current.next.prev = @current
|
193
|
+
end
|
135
194
|
target_node.remove!
|
195
|
+
self.size -= 1
|
136
196
|
end
|
137
|
-
self.tail = @current if tail === target_node
|
138
|
-
self.head = @current if head === target_node
|
139
|
-
self.size -= 1
|
140
197
|
end
|
141
198
|
|
199
|
+
|
142
200
|
# return number cleared
|
143
201
|
def clear
|
144
202
|
rc = 0
|
145
|
-
node = head
|
146
|
-
position =
|
203
|
+
node = self.head
|
204
|
+
position = node
|
147
205
|
while node do
|
148
206
|
node = node.remove!
|
149
207
|
rc += 1
|
150
|
-
break if position
|
208
|
+
break if position.equal?(node)
|
151
209
|
end
|
152
210
|
|
153
211
|
@current = nil
|
@@ -163,8 +221,8 @@ module SknUtils
|
|
163
221
|
|
164
222
|
# perform each() or return enumerator
|
165
223
|
def each(&block)
|
166
|
-
@current = head
|
167
|
-
position = head
|
224
|
+
@current = self.head
|
225
|
+
position = self.head
|
168
226
|
if block_given?
|
169
227
|
while position do
|
170
228
|
block.call( position.value.dup )
|
@@ -184,13 +242,13 @@ module SknUtils
|
|
184
242
|
|
185
243
|
# convert self to a value array
|
186
244
|
def to_a
|
187
|
-
@current = head
|
188
|
-
position = head
|
245
|
+
@current = self.head
|
246
|
+
position = self.head
|
189
247
|
result = []
|
190
248
|
while position do
|
191
249
|
result << position.value.dup
|
192
250
|
position = position.next
|
193
|
-
break if position
|
251
|
+
break if position.equal?(@current)
|
194
252
|
end
|
195
253
|
result
|
196
254
|
end
|
@@ -206,33 +264,34 @@ module SknUtils
|
|
206
264
|
else
|
207
265
|
@sort_condition
|
208
266
|
end
|
209
|
-
sorted = merge_sort(to_a)
|
267
|
+
sorted = merge_sort(self.to_a)
|
210
268
|
clear
|
211
269
|
sorted.each {|item| insert(item) }
|
212
|
-
size
|
270
|
+
self.size
|
213
271
|
end
|
214
272
|
|
215
|
-
|
273
|
+
protected
|
216
274
|
|
217
275
|
attr_accessor :head, :tail
|
218
276
|
|
219
277
|
def find_by_value(value)
|
220
|
-
return nil if
|
221
|
-
|
222
|
-
target =
|
223
|
-
|
224
|
-
|
225
|
-
target =
|
226
|
-
|
278
|
+
return nil if value.nil? || self.size == 0
|
279
|
+
stop_node = self.head
|
280
|
+
target = stop_node
|
281
|
+
rtn_node = nil
|
282
|
+
while !target.match_by_value(value)
|
283
|
+
target = target.next
|
284
|
+
break if stop_node.equal?(target)
|
227
285
|
end
|
286
|
+
target = nil unless target.match_by_value(value)
|
228
287
|
target
|
229
288
|
end
|
230
289
|
|
231
290
|
def find_by_index(index)
|
232
|
-
return nil if
|
233
|
-
node = head
|
234
|
-
node = node.next while ((index -= 1) > 0
|
235
|
-
@current = node
|
291
|
+
return nil if ( index > self.size || index < 1 )
|
292
|
+
node = self.head
|
293
|
+
node = node.next while ( (index -= 1) > 0 )
|
294
|
+
@current = node
|
236
295
|
node
|
237
296
|
end
|
238
297
|
|
@@ -240,26 +299,20 @@ module SknUtils
|
|
240
299
|
# arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
|
241
300
|
def merge_sort(arr)
|
242
301
|
return arr if arr.size < 2
|
243
|
-
|
244
302
|
middle = arr.size / 2
|
245
|
-
|
246
|
-
|
247
|
-
right = merge_sort(arr[middle..arr.size])
|
248
|
-
|
303
|
+
left = merge_sort(arr[0...middle])
|
304
|
+
right = merge_sort(arr[middle..arr.size])
|
249
305
|
merge(left, right)
|
250
306
|
end
|
251
307
|
|
252
308
|
def merge(left, right)
|
253
309
|
sorted = []
|
254
|
-
|
255
310
|
while left.any? && right.any?
|
256
|
-
|
257
311
|
if @active_sort_condition.call(left.first, right.first)
|
258
312
|
sorted.push right.shift
|
259
313
|
else
|
260
314
|
sorted.push left.shift
|
261
315
|
end
|
262
|
-
|
263
316
|
end
|
264
317
|
|
265
318
|
sorted + left + right
|
@@ -1,3 +1,26 @@
|
|
1
|
+
##
|
2
|
+
# File <SknUtils>/lib/skn_utils/lists/doubly_linked_list.rb
|
3
|
+
#
|
4
|
+
# ll = SknUtils::Lists::DoublyLinkedList.new(*vargs, &compare_key_proc)
|
5
|
+
# - or -
|
6
|
+
# ll = SknUtils::Lists::DoublyLinkedList.new(1,2,3,4,5) {|element| element[:key] }
|
7
|
+
# - or -
|
8
|
+
# ll = SknUtils::Lists::DoublyLinkedList.new(
|
9
|
+
# {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
|
10
|
+
# ) {|el| el[:key] }
|
11
|
+
# - or -
|
12
|
+
# cmp_proc = lambda { |el| el[:key] }
|
13
|
+
# vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
|
14
|
+
# ll = SknUtils::Lists::DoublyLinkedList.new(*vargs, &cmp_proc)
|
15
|
+
###
|
16
|
+
# value = ll.first
|
17
|
+
# value = ll.at_index(4)
|
18
|
+
# count = ll.insert({key: 'anyValue'})
|
19
|
+
# ...
|
20
|
+
# count = ll.sort! -- defaults to :asc
|
21
|
+
# count = ll.sort!(:desc)
|
22
|
+
# count = ll.sort!() {|a,b| a[:key] <= b[:key] }
|
23
|
+
##
|
1
24
|
|
2
25
|
module SknUtils
|
3
26
|
module Lists
|
@@ -127,14 +150,26 @@ module SknUtils
|
|
127
150
|
def remove(value)
|
128
151
|
target_node = find_by_value(value)
|
129
152
|
if target_node
|
130
|
-
|
131
|
-
|
132
|
-
|
153
|
+
if size == 1 # will become zero
|
154
|
+
@current = nil
|
155
|
+
self.head = nil
|
156
|
+
self.tail = nil
|
157
|
+
elsif target_node.prev.nil? # top
|
158
|
+
@current = target_node.next
|
159
|
+
@current.prev = nil
|
160
|
+
self.head = @current
|
161
|
+
elsif target_node.next.nil? # bottom
|
162
|
+
@current = target_node.prev
|
163
|
+
@current.next = nil
|
164
|
+
self.tail = @current
|
165
|
+
else # middle
|
166
|
+
@current = target_node.prev
|
167
|
+
@current.next = target_node.next
|
168
|
+
target_node.next.prev = @current
|
169
|
+
end
|
133
170
|
target_node.remove!
|
171
|
+
self.size -= 1
|
134
172
|
end
|
135
|
-
self.tail = @current if tail === target_node
|
136
|
-
self.head = @current if head === target_node
|
137
|
-
self.size -= 1
|
138
173
|
end
|
139
174
|
|
140
175
|
# return number cleared
|
@@ -215,13 +250,12 @@ module SknUtils
|
|
215
250
|
attr_accessor :head, :tail
|
216
251
|
|
217
252
|
def find_by_value(value)
|
218
|
-
return nil if head.nil?
|
253
|
+
return nil if head.nil? || value.nil? || size == 0
|
219
254
|
prior = head
|
220
255
|
target = prior
|
221
256
|
while target and not target.match_by_value(value)
|
222
257
|
prior = target
|
223
258
|
target = prior.next
|
224
|
-
@current = target if target
|
225
259
|
end
|
226
260
|
target
|
227
261
|
end
|
@@ -16,26 +16,26 @@ module SknUtils
|
|
16
16
|
|
17
17
|
case strategy
|
18
18
|
when :single # after logic
|
19
|
-
|
19
|
+
if anchor_node
|
20
|
+
@next = anchor_node.next
|
21
|
+
anchor_node.next = self
|
22
|
+
end
|
20
23
|
when :before
|
21
24
|
@prev = anchor_node.prev if anchor_node
|
22
|
-
@next = anchor_node
|
23
25
|
anchor_node.prev = self if anchor_node
|
26
|
+
@next = anchor_node
|
24
27
|
when :after
|
25
|
-
@prev = anchor_node
|
26
28
|
@next = anchor_node.next if anchor_node
|
27
29
|
anchor_node.next = self if anchor_node
|
28
|
-
@
|
30
|
+
@prev = anchor_node
|
29
31
|
when :circle_before
|
30
32
|
@prev = anchor_node ? anchor_node.prev : self
|
31
|
-
@next = anchor_node ? anchor_node : self
|
32
33
|
anchor_node.prev = self if anchor_node
|
33
|
-
@
|
34
|
+
@next = anchor_node ? anchor_node : self
|
34
35
|
when :circle_after
|
35
|
-
@prev = anchor_node ? anchor_node : self
|
36
36
|
@next = anchor_node ? anchor_node.next : self
|
37
37
|
anchor_node.next = self if anchor_node
|
38
|
-
@
|
38
|
+
@prev = anchor_node ? anchor_node : self
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -1,3 +1,26 @@
|
|
1
|
+
##
|
2
|
+
# File <SknUtils>/lib/skn_utils/lists/linked_list.rb
|
3
|
+
#
|
4
|
+
# ll = SknUtils::Lists::LinkedList.new(*vargs, &compare_key_proc)
|
5
|
+
# - or -
|
6
|
+
# ll = SknUtils::Lists::LinkedList.new(1,2,3,4,5) {|element| element[:key] }
|
7
|
+
# - or -
|
8
|
+
# ll = SknUtils::Lists::LinkedList.new(
|
9
|
+
# {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
|
10
|
+
# ) {|el| el[:key] }
|
11
|
+
# - or -
|
12
|
+
# cmp_proc = lambda { |el| el[:key] }
|
13
|
+
# vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
|
14
|
+
# ll = SknUtils::Lists::LinkedList.new(*vargs, &cmp_proc)
|
15
|
+
###
|
16
|
+
# value = ll.first
|
17
|
+
# value = ll.at_index(4)
|
18
|
+
# count = ll.insert({key: 'anyValue'})
|
19
|
+
# ...
|
20
|
+
# count = ll.sort! -- defaults to :asc
|
21
|
+
# count = ll.sort!(:desc)
|
22
|
+
# count = ll.sort!() {|a,b| a[:key] <= b[:key] }
|
23
|
+
##
|
1
24
|
|
2
25
|
module SknUtils
|
3
26
|
module Lists
|
@@ -50,7 +73,7 @@ module SknUtils
|
|
50
73
|
@current.value rescue nil
|
51
74
|
end
|
52
75
|
|
53
|
-
#
|
76
|
+
# +int position from current node
|
54
77
|
def nth(index)
|
55
78
|
node = @current
|
56
79
|
while index > 1 and node and node.next
|
@@ -60,8 +83,6 @@ module SknUtils
|
|
60
83
|
end
|
61
84
|
# no reverse or prev for Single List
|
62
85
|
current
|
63
|
-
rescue NoMethodError
|
64
|
-
nil
|
65
86
|
end
|
66
87
|
|
67
88
|
# return node at positive index from head
|
@@ -119,10 +140,11 @@ module SknUtils
|
|
119
140
|
|
120
141
|
# return remaining size
|
121
142
|
def remove(value)
|
122
|
-
|
123
|
-
@current
|
124
|
-
|
125
|
-
self.
|
143
|
+
prior, target_node = find_by_value(value)
|
144
|
+
@current = prior.nil? ? target_node.next : prior
|
145
|
+
@current.next = target_node.remove! if @current && target_node
|
146
|
+
self.tail = @current.next if @current && tail === target_node
|
147
|
+
self.head = @current.next if @current && head === target_node
|
126
148
|
self.size -= 1
|
127
149
|
end
|
128
150
|
|
@@ -203,19 +225,19 @@ module SknUtils
|
|
203
225
|
attr_accessor :head, :tail
|
204
226
|
|
205
227
|
def find_by_value(value)
|
206
|
-
return [
|
207
|
-
prior
|
228
|
+
return [@current, nil] if head.nil? || value.nil?
|
229
|
+
prior = head
|
208
230
|
target = prior
|
209
231
|
while target and not target.match_by_value(value)
|
210
232
|
prior = target
|
211
|
-
target =
|
212
|
-
@current =
|
233
|
+
target = target.next
|
234
|
+
@current = prior if target
|
213
235
|
end
|
214
236
|
[prior, target]
|
215
237
|
end
|
216
238
|
|
217
239
|
def find_by_index(index)
|
218
|
-
return nil if head.nil?
|
240
|
+
return nil if head.nil? || index < 1 || index > size
|
219
241
|
node = head
|
220
242
|
node = node.next while ((index -= 1) > 0 and node.next)
|
221
243
|
@current = node if node
|