skn_utils 3.3.4 → 3.3.5
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/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
|