Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/sequence.e | 39 | 40 | 97.50% | 700 | 734 | 95.37% | 34 |
Routine | Executed | Lines | Unexecuted | |
add_item() | 0 | 10 | 0.00% | 10 |
columnize() | 25 | 30 | 83.33% | 5 |
mapping() | 10 | 13 | 76.92% | 3 |
breakup() | 46 | 48 | 95.83% | 2 |
build_list() | 22 | 24 | 91.67% | 2 |
rotate() | 15 | 17 | 88.24% | 2 |
vslice() | 18 | 20 | 90.00% | 2 |
can_add() | 9 | 10 | 90.00% | 1 |
extract() | 7 | 8 | 87.50% | 1 |
fetch() | 7 | 8 | 87.50% | 1 |
mid() | 11 | 12 | 91.67% | 1 |
patch() | 11 | 12 | 91.67% | 1 |
split() | 48 | 49 | 97.96% | 1 |
split_any() | 30 | 31 | 96.77% | 1 |
store() | 18 | 19 | 94.74% | 1 |
apply() | 5 | 5 | 100.00% | 0 |
combine() | 18 | 18 | 100.00% | 0 |
filter() | 110 | 110 | 100.00% | 0 |
filter_alpha() | 2 | 2 | 100.00% | 0 |
flatten() | 19 | 19 | 100.00% | 0 |
join() | 8 | 8 | 100.00% | 0 |
linear() | 9 | 9 | 100.00% | 0 |
minsize() | 4 | 4 | 100.00% | 0 |
pad_head() | 4 | 4 | 100.00% | 0 |
pad_tail() | 4 | 4 | 100.00% | 0 |
pivot() | 9 | 9 | 100.00% | 0 |
project() | 8 | 8 | 100.00% | 0 |
remove_all() | 19 | 19 | 100.00% | 0 |
remove_dups() | 24 | 24 | 100.00% | 0 |
remove_item() | 9 | 9 | 100.00% | 0 |
remove_subseq() | 19 | 19 | 100.00% | 0 |
repeat_pattern() | 10 | 10 | 100.00% | 0 |
replace_all() | 15 | 15 | 100.00% | 0 |
retain_all() | 18 | 18 | 100.00% | 0 |
reverse() | 21 | 21 | 100.00% | 0 |
shuffle() | 8 | 8 | 100.00% | 0 |
sim_index() | 37 | 37 | 100.00% | 0 |
slice() | 10 | 10 | 100.00% | 0 |
transform() | 10 | 10 | 100.00% | 0 |
valid_index() | 8 | 8 | 100.00% | 0 |
# | Executed | |
1 | -- (c) Copyright - See License.txt | |
2 | -- | |
3 | namespace stdseq | |
4 | ||
5 | --**** | |
6 | -- == Sequence Manipulation | |
7 | -- | |
8 | -- < | |
9 | include std/error.e | |
10 | include std/search.e | |
11 | ||
12 | include std/sort.e | |
13 | include std/math.e | |
14 | include std/types.e | |
15 | ||
16 | --**** | |
17 | -- === Constants | |
18 | ||
19 | public enum | |
20 | 101 | ADD_PREPEND, |
21 | 101 | ADD_APPEND, |
22 | 101 | ADD_SORT_UP, |
23 | 101 | ADD_SORT_DOWN |
24 | ||
25 | public constant | |
26 | 101 | ROTATE_LEFT = 1, |
27 | 101 | ROTATE_RIGHT = -1 |
28 | ||
29 | --**** | |
30 | -- === Basic routines | |
31 | -- | |
32 | ||
33 | --** | |
34 | -- Checks whether two objects can be legally added together. | |
35 | -- | |
36 | -- Parameters: | |
37 | -- # ##a## : one of the objects to test for compatible shape | |
38 | -- # ##b## : the other object | |
39 | -- | |
40 | -- Returns: | |
41 | -- An **integer**, 1 if an addition (or any of the [[:Relational operators]]) | |
42 | -- are possible between ##a## and ##b##, else 0. | |
43 | -- | |
44 | -- Example 1: | |
45 | -- | |
46 | -- i = can_add({1,2,3},{4,5}) | |
47 | -- -- i is 0 | |
48 | -- | |
49 | -- i = can_add({1,2,3},4) | |
50 | -- -- i is 1 | |
51 | -- | |
52 | -- i = can_add({1,2,3},{4,{5,6},7}) | |
53 | -- -- i is 1 | |
54 | -- | |
55 | -- | |
56 | -- See Also: | |
57 | -- [[:linear]] | |
58 | ||
59 | 7 | |
60 | 7 | if atom(a) or atom(b) then |
61 | 4 | return 1 |
62 | end if | |
63 | 3 | if length(a)!=length(b) then |
64 | 1 | return 0 |
65 | end if | |
66 | 2 | for i=1 to length(a) do |
67 | 4 | if not can_add(a[i], b[i]) then |
68 | 0 | return 0 |
69 | end if | |
70 | 4 | end for |
71 | 2 | return 1 |
72 | end function | |
73 | ||
74 | --** | |
75 | -- Retrieves an element nested arbitrarily deep into a sequence. | |
76 | -- | |
77 | -- Parameters: | |
78 | -- # ##source## : the sequence from which to fetch | |
79 | -- # ##indexes## : a sequence of integers, the path to follow to reach the | |
80 | -- element to return. | |
81 | -- | |
82 | -- Returns: | |
83 | -- An **object**, which is ##source[indexes[1]][indexes[2]]...[indexes[$]]## | |
84 | -- | |
85 | -- Errors: | |
86 | -- If the path cannot be followed to its end, an error about reading a | |
87 | -- nonexistent element, or subscripting an atom, will occur. | |
88 | -- | |
89 | -- Comments: | |
90 | -- The last element of ##indexes## may be a pair {lower,upper}, in which case | |
91 | -- a slice of the innermost referenced sequence is returned. | |
92 | -- | |
93 | -- Example 1: | |
94 | -- | |
95 | -- x = fetch({0,1,2,3,{"abc","def","ghi"},6},{5,2,3}) | |
96 | -- -- x is 'f', or 102. | |
97 | -- | |
98 | -- | |
99 | -- See Also: | |
100 | -- [[:store]], [[:Subscripting of Sequences]] | |
101 | ||
102 | 1 | |
103 | object x | |
104 | ||
105 | 1 | for i=1 to length(indexes)-1 do |
106 | 2 | source = source[indexes[i]] |
107 | 2 | end for |
108 | 1 | x = indexes[$] |
109 | 1 | if atom(x) then |
110 | 1 | return source[x] |
111 | else | |
112 | 0 | return source[x[1]..x[2]] |
113 | end if | |
114 | end function | |
115 | ||
116 | --** | |
117 | -- Stores something at a location nested arbitrarily deep into a sequence. | |
118 | -- | |
119 | -- Parameters: | |
120 | -- # ##target## : the sequence in which to store something | |
121 | -- # ##indexes## : a sequence of integers, the path to follow to reach the | |
122 | -- place where to store | |
123 | -- # ##x## : the object to store. | |
124 | -- | |
125 | -- Returns: | |
126 | -- A **sequence**, a **copy** of ##target## with the specified place | |
127 | -- ##indexes## modified by storing ##x## into it. | |
128 | -- | |
129 | -- Errors: | |
130 | -- If the path to storage location cannot be followed to its end, or an | |
131 | -- index is not what one would expect or is not valid, an error about illegal | |
132 | -- sequence operations will occur. | |
133 | -- | |
134 | -- Comments: | |
135 | -- If the last element of ##indexes## is a pair of integers, ##x## will be | |
136 | -- stored as a slice three, the bounding indexes being given in the pair as {lower,upper}.. | |
137 | -- | |
138 | -- In Euphoria, you can never modify an object by passing it to a routine. | |
139 | -- You have to get a modified copy and then assign it back to the original. | |
140 | -- | |
141 | -- Example 1: | |
142 | -- | |
143 | -- s = store({0,1,2,3,{"abc","def","ghi"},6},{5,2,3},108) | |
144 | -- -- s is {0,1,2,3,{"abc","del","ghi"},6} | |
145 | -- | |
146 | -- | |
147 | -- See Also: | |
148 | -- [[:fetch]], [[:Subscripting of Sequences]] | |
149 | ||
150 | 1 | |
151 | sequence partials,result,branch | |
152 | object last_idx | |
153 | ||
154 | 1 | partials = repeat(target,length(indexes)-1) |
155 | 1 | branch = target |
156 | 1 | for i=1 to length(indexes)-1 do |
157 | 2 | branch=branch[indexes[i]] |
158 | 2 | partials[i]=branch |
159 | 2 | end for |
160 | ||
161 | 1 | last_idx = indexes[$] |
162 | 1 | if atom(last_idx) then |
163 | 1 | branch[last_idx]=x |
164 | else | |
165 | 0 | branch[last_idx[1]..last_idx[2]]=x |
166 | end if | |
167 | ||
168 | 1 | partials = prepend(partials,0) -- avoids computing temp=i+1 a few times |
169 | ||
170 | 1 | for i=length(indexes)-1 to 2 by -1 do |
171 | 1 | result = partials[i] |
172 | 1 | result[indexes[i]] = branch |
173 | 1 | branch = result |
174 | 1 | end for |
175 | 1 | target[indexes[1]] = branch |
176 | 1 | return target |
177 | end function | |
178 | ||
179 | --** | |
180 | -- Checks whether an index exists on a sequence. | |
181 | -- | |
182 | -- Parameters: | |
183 | -- # ##s## : the sequence for which to check | |
184 | -- # ##x## : an object, the index to check. | |
185 | -- | |
186 | -- Returns: | |
187 | -- An **integer**, 1 if ##s[x]## makes sense, else 0. | |
188 | -- | |
189 | -- Example 1: | |
190 | -- | |
191 | -- i = valid_index({51,27,33,14},2) | |
192 | -- -- i is 1 | |
193 | -- | |
194 | -- | |
195 | -- See Also: | |
196 | -- [[:Subscripting of Sequences]] | |
197 | ||
198 | 83 | |
199 | 83 | if not atom(x) then |
200 | 2 | return 0 |
201 | end if | |
202 | 81 | if x < 1 then |
203 | 3 | return 0 |
204 | end if | |
205 | 78 | if floor(x) > length(st) then |
206 | 2 | return 0 |
207 | end if | |
208 | 76 | return 1 |
209 | end function | |
210 | ||
211 | --** | |
212 | -- Rotates a slice of a sequence. | |
213 | -- | |
214 | -- Parameters: | |
215 | -- # ##source## : sequence to be rotated | |
216 | -- # ##shift## : direction and count to be shifted (##ROTATE_LEFT## or ##ROTATE_RIGHT##) | |
217 | -- # ##start## : starting position for shift, defaults o 1 | |
218 | -- # ##stop## : stopping position for shift, defaults to ##length(source)## | |
219 | -- | |
220 | -- Comments: | |
221 | -- | |
222 | -- Use ##amount * direction## to specify the shift. direction is either ##ROTATE_LEFT## | |
223 | -- or ##ROTATE_RIGHT##. This enables to shift multiple places in a single call. | |
224 | -- For instance, use {{{ROTATE_LEFT * 5}}} to rotate left, 5 | |
225 | -- positions. | |
226 | -- | |
227 | -- A null shift does nothing and returns source unchanged. | |
228 | -- | |
229 | -- Example 1: | |
230 | -- | |
231 | -- s = rotate({1, 2, 3, 4, 5}, ROTATE_LEFT) | |
232 | -- -- s is {2, 3, 4, 5, 1} | |
233 | -- | |
234 | -- | |
235 | -- Example 2: | |
236 | -- | |
237 | -- s = rotate({1, 2, 3, 4, 5}, ROTATE_RIGHT * 2) | |
238 | -- -- s is {4, 5, 1, 2, 3} | |
239 | -- | |
240 | -- | |
241 | -- Example 3: | |
242 | -- | |
243 | -- s = rotate({11,13,15,17,19,23}, ROTATE_LEFT, 2, 5) | |
244 | -- -- s is {11,15,17,19,13,23} | |
245 | -- | |
246 | -- | |
247 | -- Example 4: | |
248 | -- | |
249 | -- s = rotate({11,13,15,17,19,23}, ROTATE_RIGHT, 2, 5) | |
250 | -- -- s is {11,19,13,15,17,23} | |
251 | -- | |
252 | -- | |
253 | -- See Also: | |
254 | -- [[:slice]], [[:head]], [[:tail]] | |
255 | ||
256 | 16 | |
257 | sequence shifted | |
258 | integer len | |
259 | integer lSize | |
260 | ||
261 | 16 | if start >= stop or length(source)=0 or not shift then |
262 | 4 | return source |
263 | end if | |
264 | ||
265 | 12 | if not valid_index(source, start) then |
266 | 0 | crash("sequence:rotate(): invalid 'start' parameter %d", start) |
267 | end if | |
268 | ||
269 | 12 | if not valid_index(source, stop) then |
270 | 0 | crash("sequence:rotate(): invalid 'stop' parameter %d", stop) |
271 | end if | |
272 | ||
273 | 12 | len = stop - start + 1 |
274 | 12 | lSize = remainder(shift, len) |
275 | 12 | if lSize = 0 then |
276 | 2 | return source |
277 | end if | |
278 | ||
279 | 10 | if lSize < 0 then -- convert right shift to left shift |
280 | 5 | lSize += len |
281 | end if | |
282 | ||
283 | 10 | shifted = source[start .. start + lSize-1] |
284 | 10 | source[start .. stop - lSize] = source[start + lSize .. stop] |
285 | 10 | source[stop - lSize + 1.. stop] = shifted |
286 | 10 | return source |
287 | end function | |
288 | ||
289 | --** | |
290 | -- Converts a set of sub sequences into a set of 'columns'. | |
291 | -- | |
292 | -- Parameters: | |
293 | -- # ##source## : sequence containing the sub-sequences | |
294 | -- # ##cols## : either a specific column number or a set of column numbers. | |
295 | -- Default is 0, which returns the maximum number of columns. | |
296 | -- # ##defval## : an object. Used when a column value is not available. Default is 0 | |
297 | -- | |
298 | -- Comments: | |
299 | -- Any atoms found in ##source## are treated as if they are a 1-element sequence. | |
300 | -- | |
301 | -- Example 1: | |
302 | -- | |
303 | -- s = columnize({{1, 2}, {3, 4}, {5, 6}}) | |
304 | -- -- s is { {1,3,5}, {2,4,6}} | |
305 | -- | |
306 | -- | |
307 | -- Example 2: | |
308 | -- | |
309 | -- s = columnize({{1, 2}, {3, 4}, {5, 6, 7}}) | |
310 | -- -- s is { {1,3,5}, {2,4,6}, {0,0,7} } | |
311 | -- s = columnize({{1, 2}, {3, 4}, {5, 6, 7},,-999}) -- Change the not-available value. | |
312 | -- -- s is { {1,3,5}, {2,4,6}, {-999,-999,7} } | |
313 | -- | |
314 | -- | |
315 | -- Example 3: | |
316 | -- | |
317 | -- s = columnize({{1, 2}, {3, 4}, {5, 6, 7}}, 2) | |
318 | -- -- s is { {2,4,6} } -- Column 2 only | |
319 | -- | |
320 | -- | |
321 | -- Example 4: | |
322 | -- | |
323 | -- s = columnize({{1, 2}, {3, 4}, {5, 6, 7}}, {2,1}) | |
324 | -- -- s is { {2,4,6}, {1,3,5} } -- Column 2 then column 1 | |
325 | -- | |
326 | -- | |
327 | -- Example 5: | |
328 | -- | |
329 | -- s = columnize({"abc", "def", "ghi"}) | |
330 | -- -- s is {"adg", "beh", "cfi" } | |
331 | -- | |
332 | ||
333 | ||
334 | 8 | |
335 | sequence result | |
336 | sequence collist | |
337 | ||
338 | 8 | if sequence(cols) then |
339 | 7 | collist = cols |
340 | else | |
341 | 1 | collist = {cols} |
342 | end if | |
343 | ||
344 | 8 | if length(collist) = 0 then |
345 | 6 | cols = 0 |
346 | 6 | for i = 1 to length(source) do |
347 | 17 | if atom(source[i]) then |
348 | 0 | if cols = 0 then |
349 | 0 | cols = 1 |
350 | end if | |
351 | else | |
352 | 17 | if cols < length(source[i]) then |
353 | 8 | cols = length(source[i]) |
354 | end if | |
355 | end if | |
356 | 17 | end for |
357 | 6 | for i = 1 to cols do |
358 | 16 | collist &= i |
359 | 16 | end for |
360 | end if | |
361 | ||
362 | 8 | result = repeat({}, length(collist)) |
363 | 8 | for i = 1 to length(collist) do |
364 | 19 | integer col = collist[i] |
365 | 19 | for j = 1 to length(source) do |
366 | 55 | if atom(source[j]) then |
367 | 0 | if 1 < col then |
368 | 0 | result[i] = append(result[i], defval) |
369 | else | |
370 | 0 | result[i] = append(result[i], source[j][col]) |
371 | end if | |
372 | else | |
373 | 55 | if length(source[j]) < col then |
374 | 5 | result[i] = append(result[i], defval) |
375 | else | |
376 | 50 | result[i] = append(result[i], source[j][col]) |
377 | end if | |
378 | end if | |
379 | 55 | end for |
380 | 19 | end for |
381 | ||
382 | 8 | return result |
383 | end function | |
384 | ||
385 | ||
386 | --** | |
387 | -- Apply a function to every element of a sequence returning a new sequence of | |
388 | -- the same size. | |
389 | -- | |
390 | -- Parameters: | |
391 | -- * ##source## : the sequence to map | |
392 | -- * ##rid## : the [[:routine_id]] of function to use as converter | |
393 | -- * ##userdata## : an object passed to each invocation of ##rid##. If omitted, | |
394 | -- {} is used. | |
395 | -- | |
396 | -- Returns: | |
397 | -- A **sequence**, the length of ##source##. Each element there is the | |
398 | -- corresponding element in ##source## mapped using the routine referred to by ##rid##. | |
399 | -- | |
400 | -- Comments: | |
401 | -- The supplied routine must take two parameters. The type of the first parameter must | |
402 | -- be compatible with all the elements in ##source##. The second parameter is | |
403 | -- an ##object## containing ##userdata##. | |
404 | -- | |
405 | -- Example 1: | |
406 | -- | |
407 | -- function greeter(object o, object d) | |
408 | -- return o[1] & ", " & o[2] & d | |
409 | -- end function | |
410 | -- | |
411 | -- s = apply({{"Hello", "John"}, {"Goodbye", "John"}}, routine_id("greeter"), "!") | |
412 | -- -- s is {"Hello, John!", "Goodbye, John!"} | |
413 | -- | |
414 | -- | |
415 | -- See Also: | |
416 | -- [[:filter]] | |
417 | ||
418 | 1 | |
419 | 1 | for a = 1 to length(source) do |
420 | 4 | source[a] = call_func(rid, {source[a], userdata}) |
421 | 4 | end for |
422 | 1 | return source |
423 | end function | |
424 | ||
425 | --** | |
426 | -- Each item from ##source_arg## found in ##from_set## is changed into the | |
427 | -- corresponding item in ##to_set## | |
428 | -- | |
429 | -- Parameters: | |
430 | -- # ##source_arg## : Any Euphoria object to be transformed. | |
431 | -- # ##from_set## : A sequence of objects representing the only items from | |
432 | -- ##source_arg## that are actually transformed. | |
433 | -- # ##to_set## : A sequence of objects representing the transformed equivalents | |
434 | -- of those found in ##from_set##. | |
435 | -- # ##one_level## : An integer. 0 (the default) means that mapping applies to | |
436 | -- every atom in every level of sub-sequences. 1 means that | |
437 | -- mapping only applies to the items at the first level | |
438 | -- in ##source_arg##. | |
439 | -- | |
440 | -- Returns: | |
441 | -- An **object**, The transformed version of ##source_arg##. | |
442 | -- | |
443 | -- Comments: | |
444 | -- * When ##one_level## is zero or omitted, for each item in ##source_arg##, | |
445 | -- ** if it is an atom then it may be transformed | |
446 | -- ** if it is a sequence, then the mapping is performed recursively on the | |
447 | -- sequence. | |
448 | -- ** This option required ##from_set## to only contain atoms and contain no | |
449 | -- sub-sequences. | |
450 | -- * When ##one_level## is not zero, for each item in ##source_arg##, | |
451 | -- ** regardless of whether it is an atom or sequence, if it is found in ##from_set## | |
452 | -- then it is mapped to the corresponding object in ##to_set##.. | |
453 | -- * Mapping occurs when an item in ##source_arg## is found in ##from_set##, | |
454 | -- then it is replaced by the corresponding object in ##to_set##. | |
455 | -- | |
456 | -- Example 1: | |
457 | -- | |
458 | -- res = mapping("The Cat in the Hat", "aeiou", "AEIOU") | |
459 | -- -- res is now "ThE CAt In thE HAt" | |
460 | -- | |
461 | ||
462 | 10 | |
463 | integer pos | |
464 | ||
465 | 10 | if atom(source_arg) then |
466 | 0 | pos = find(source_arg, from_set) |
467 | 0 | if pos >= 1 and pos <= length(to_set) then |
468 | 0 | source_arg = to_set[pos] |
469 | end if | |
470 | else | |
471 | 10 | for i = 1 to length(source_arg) do |
472 | 161 | if atom(source_arg[i]) or one_level then |
473 | 160 | pos = find(source_arg[i], from_set) |
474 | 160 | if pos >= 1 and pos <= length(to_set) then |
475 | 90 | source_arg[i] = to_set[pos] |
476 | end if | |
477 | else | |
478 | 1 | source_arg[i] = mapping(source_arg[i], from_set, to_set) |
479 | end if | |
480 | 161 | end for |
481 | end if | |
482 | ||
483 | 10 | return source_arg |
484 | end function | |
485 | ||
486 | --**** | |
487 | -- Signature: | |
488 | -- | |
489 | -- | |
490 | -- Description: | |
491 | -- Return the length of a sequence. | |
492 | -- | |
493 | -- Parameters: | |
494 | -- # ##target## : the sequence being queried | |
495 | -- | |
496 | -- Returns: | |
497 | -- An **integer**, the number of elements ##target## has. | |
498 | -- | |
499 | -- Comments: | |
500 | -- The length of each sequence is stored internally by the | |
501 | -- interpreter for fast access. In some other languages this | |
502 | -- operation requires a search through memory for an end marker. | |
503 | -- | |
504 | -- Example 1: | |
505 | -- | |
506 | -- length({{1,2}, {3,4}, {5,6}}) -- 3 | |
507 | -- length("") -- 0 | |
508 | -- length({}) -- 0 | |
509 | -- | |
510 | -- | |
511 | -- See Also: | |
512 | -- [[:append]], [[:prepend]], [[:& -> amp_concat]] | |
513 | ||
514 | --** | |
515 | -- Reverse the order of elements in a sequence. | |
516 | -- | |
517 | -- Parameters: | |
518 | -- # ##target## : the sequence to reverse. | |
519 | -- # ##pFrom## : an integer, the starting point. Defaults to 1. | |
520 | -- # ##pTo## : an integer, the end point. Defaults to 0. | |
521 | -- | |
522 | -- Returns: | |
523 | -- A **sequence**, if ##target## is a sequence, the same length as ##target## | |
524 | -- and the same elements, but those with index between ##pFrom## and ##pTo## | |
525 | -- appear in reverse order. | |
526 | -- | |
527 | -- Comments: | |
528 | -- In the result sequence, some or all top-level elements appear in reverse order compared | |
529 | -- to the original sequence. This does not reverse any sub-sequences found in the original | |
530 | -- sequence.\\ | |
531 | -- The ##pTo## parameter can be negative, which indicates an offset from the last element. | |
532 | -- Thus {{{-1}}} means the second-last element and {{{0}}} means the last element. | |
533 | -- | |
534 | -- Example 1: | |
535 | -- | |
536 | -- reverse({1,3,5,7}) -- {7,5,3,1} | |
537 | -- reverse({1,3,5,7,9}, 2, -1) -- {1,7,5,3,9} | |
538 | -- reverse({1,3,5,7,9}, 2) -- {1,9,7,5,3} | |
539 | -- reverse({{1,2,3}, {4,5,6}}) -- {{4,5,6}, {1,2,3}} | |
540 | -- reverse({99}) -- {99} | |
541 | -- reverse({}) -- {} | |
542 | -- reverse(42) -- 42 | |
543 | -- | |
544 | ||
545 | 21 | |
546 | integer uppr, n, lLimit | |
547 | sequence t | |
548 | ||
549 | 21 | if atom(target) or length(target) < 2 then |
550 | 3 | return target |
551 | end if | |
552 | ||
553 | 18 | n = length(target) |
554 | 18 | if pFrom < 1 then |
555 | 1 | pFrom = 1 |
556 | end if | |
557 | 18 | if pTo < 1 then |
558 | 16 | pTo = n + pTo |
559 | end if | |
560 | 18 | if pTo < pFrom or pFrom >= n then |
561 | 2 | return target |
562 | end if | |
563 | 16 | if pTo > n then |
564 | 1 | pTo = n |
565 | end if | |
566 | ||
567 | 16 | lLimit = floor((pFrom+pTo-1)/2) |
568 | 16 | t = target |
569 | 16 | uppr = pTo |
570 | 16 | for lowr = pFrom to lLimit do |
571 | 117 | t[uppr] = target[lowr] |
572 | 117 | t[lowr] = target[uppr] |
573 | 117 | uppr -= 1 |
574 | 117 | end for |
575 | 16 | return t |
576 | end function | |
577 | ||
578 | --** | |
579 | -- Shuffle the elements of a sequence. | |
580 | -- | |
581 | -- Parameters: | |
582 | -- # ##seq##: the sequence to shuffle. | |
583 | -- | |
584 | -- Returns: | |
585 | -- A **sequence** | |
586 | -- | |
587 | -- Comments: | |
588 | -- The input sequence does not have to be in any specific order and can | |
589 | -- contain duplicates. The output will be in an unpredictable order, which | |
590 | -- might even be the same as the input order. | |
591 | -- | |
592 | -- Example 1: | |
593 | -- | |
594 | -- shuffle({1,2,3,3}) -- {3,1,3,2} | |
595 | -- shuffle({1,2,3,3}) -- {2,3,1,3} | |
596 | -- shuffle({1,2,3,3}) -- {1,2,3,3} | |
597 | -- | |
598 | ||
599 | 1 | |
600 | -- 1963 shuffle algorithm written by L.E. Moses and R.V. Oakford | |
601 | ||
602 | 1 | for toIdx = length(seq) to 2 by -1 do |
603 | -- Get a random spot in the remaining items | |
604 | 9 | integer fromIdx = rand(toIdx) |
605 | ||
606 | -- Swap the newly picked item with whatever is at the receiving spot | |
607 | 9 | object swapValue = seq[fromIdx] |
608 | ||
609 | 9 | seq[fromIdx] = seq[toIdx] |
610 | 9 | seq[toIdx] = swapValue |
611 | ||
612 | 9 | end for |
613 | ||
614 | 1 | return seq |
615 | end function | |
616 | ||
617 | --**** | |
618 | -- === Building sequences | |
619 | -- | |
620 | ||
621 | --** | |
622 | -- Returns a sequence in arithmetic progression. | |
623 | -- | |
624 | -- Parameters: | |
625 | -- # ##start## : the initial value from which to start | |
626 | -- # ##increment## : the value to recursively add to ##start## to get new elements | |
627 | -- # ##count## : an integer, the number of additions to perform. | |
628 | -- | |
629 | -- Returns: | |
630 | -- An **object**, either 0 on failure or | |
631 | -- ##{start, start+increment,...,start+count*increment}## | |
632 | -- | |
633 | -- Comments: | |
634 | -- | |
635 | -- If ##count## is negative, or if adding ##start## to ##increment## would | |
636 | -- prove to be impossible, then 0 is returned. Otherwise, a sequence, of length | |
637 | -- ##count+1##, staring with ##start## and whose adjacent elements differ | |
638 | -- exactly by ##increment##, is returned. | |
639 | -- | |
640 | -- Example 1: | |
641 | -- | |
642 | -- s = linear({1,2,3},4,3) | |
643 | -- -- s is {{1,2,3},{5,6,7},{9,10,11}} | |
644 | -- | |
645 | -- | |
646 | -- See Also: | |
647 | -- [[:repeat_pattern]] | |
648 | ||
649 | 2 | |
650 | sequence result | |
651 | ||
652 | 2 | if count<0 or not can_add(start,increment) then |
653 | 1 | return 0 |
654 | end if | |
655 | 1 | result=repeat(start,count) |
656 | 1 | for i=2 to count do |
657 | 3 | start += increment |
658 | 3 | result[i] = start |
659 | 3 | end for |
660 | 1 | return result |
661 | end function | |
662 | ||
663 | --** | |
664 | -- Returns a periodic sequence, given a pattern and a count. | |
665 | -- | |
666 | -- Parameters: | |
667 | -- # ##pattern## : the sequence whose elements are to be repeated | |
668 | -- # ##count## : an integer, the number of times the pattern is to be repeated. | |
669 | -- | |
670 | -- Returns: | |
671 | -- A **sequence**, empty on failure, and of length ##count*length(pattern)## | |
672 | -- otherwise. The first elements of the returned sequence are those of | |
673 | -- ##pattern##. So are those that follow, on to the end. | |
674 | -- | |
675 | -- Example 1: | |
676 | -- | |
677 | -- s = repeat_pattern({1,2,5},3) | |
678 | -- -- s is {1,2,5,1,2,5,1,2,5} | |
679 | -- | |
680 | -- | |
681 | -- See Also: | |
682 | -- [[:repeat]], [[:linear]] | |
683 | ||
684 | 2 | |
685 | integer ls | |
686 | sequence result | |
687 | ||
688 | 2 | if count<=0 then |
689 | 1 | return {} |
690 | end if | |
691 | 1 | ls = length(pattern) |
692 | 1 | count *= ls |
693 | 1 | result=repeat(0,count) |
694 | 1 | for i=1 to count by ls do |
695 | 4 | result[i..i+ls-1] = pattern |
696 | 4 | end for |
697 | 1 | return result |
698 | end function | |
699 | ||
700 | --**** | |
701 | -- Signature: | |
702 | -- | |
703 | -- | |
704 | -- Description: | |
705 | -- Create a sequence whose all elements are identical, with given length. | |
706 | -- | |
707 | -- Parameters: | |
708 | -- # ##item## : an object, to which all elements of the result will be equal | |
709 | -- # ##count## : an atom, the requested length of the result sequence. This must | |
710 | -- be a value from zero to 0x3FFFFFFF. Any floating point values | |
711 | -- are first floored. | |
712 | -- | |
713 | -- Returns: | |
714 | -- A **sequence**, of length ##count## each element of which is ##item##. | |
715 | -- | |
716 | -- Errors: | |
717 | -- ##count## cannot be less than zero and cannot be greater than 1,073,741,823. | |
718 | -- | |
719 | -- Comments: | |
720 | -- When you repeat() a sequence or a floating-point number the | |
721 | -- interpreter does not actually make multiple copies in memory. | |
722 | -- Rather, a single copy is "pointed to" a number of times. | |
723 | -- | |
724 | -- Example 1: | |
725 | -- | |
726 | -- repeat(0, 10) -- {0,0,0,0,0,0,0,0,0,0} | |
727 | -- | |
728 | -- repeat("JOHN", 4) -- {"JOHN", "JOHN", "JOHN", "JOHN"} | |
729 | -- -- The interpreter will create only one copy of "JOHN" | |
730 | -- -- in memory and create a sequence containing four references to it. | |
731 | -- | |
732 | -- | |
733 | -- See Also: | |
734 | -- [[:repeat_pattern]], [[:linear]] | |
735 | ||
736 | --**** | |
737 | -- === Adding to sequences | |
738 | -- | |
739 | ||
740 | --**** | |
741 | -- Signature: | |
742 | -- | |
743 | -- | |
744 | -- Description: | |
745 | -- Adds an object as the last element of a sequence. | |
746 | -- | |
747 | -- Parameters: | |
748 | -- # ##source## : the sequence to add to | |
749 | -- # ##x## : the object to add | |
750 | -- | |
751 | -- Returns: | |
752 | -- A **sequence**, whose first elements are those of ##target## and whose | |
753 | -- last element is ##x##. | |
754 | -- | |
755 | -- Comments: | |
756 | -- | |
757 | -- The length of the resulting sequence will be ##length(target) + 1##, no | |
758 | -- matter what ##x## is. | |
759 | -- | |
760 | -- If ##x## is an atom this is equivalent to ##result = target & x##. If ##x## | |
761 | -- is a sequence it is not equivalent. | |
762 | -- | |
763 | -- The extra storage is allocated automatically and very efficiently with | |
764 | -- Euphoria's dynamic storage allocation. The case where ##target## itself is | |
765 | -- append()ed to (as in Example 1 below) is highly optimized. | |
766 | -- | |
767 | -- Example 1: | |
768 | -- | |
769 | -- sequence x | |
770 | -- | |
771 | -- x = {} | |
772 | -- for i = 1 to 10 do | |
773 | -- x = append(x, i) | |
774 | -- end for | |
775 | -- -- x is now {1,2,3,4,5,6,7,8,9,10} | |
776 | -- | |
777 | -- | |
778 | -- Example 2: | |
779 | -- | |
780 | -- sequence x, y, z | |
781 | -- | |
782 | -- x = {"fred", "barney"} | |
783 | -- y = append(x, "wilma") | |
784 | -- -- y is now {"fred", "barney", "wilma"} | |
785 | -- | |
786 | -- z = append(append(y, "betty"), {"bam", "bam"}) | |
787 | -- -- z is now {"fred", "barney", "wilma", "betty", {"bam", "bam"}} | |
788 | -- | |
789 | -- | |
790 | -- See Also: | |
791 | -- [[:prepend]], [[:& -> amp_concat]] | |
792 | ||
793 | --**** | |
794 | -- Signature: | |
795 | -- | |
796 | -- | |
797 | -- Description: | |
798 | -- Adds an object as the first element of a sequence. | |
799 | -- | |
800 | -- Parameters: | |
801 | -- # ##source## : the sequence to add to | |
802 | -- # ##x## : the object to add | |
803 | -- | |
804 | -- Returns: | |
805 | -- A **sequence**, whose last elements are those of ##target## and whose | |
806 | -- first element is ##x##. | |
807 | -- | |
808 | -- Comments: | |
809 | -- The length of the returned sequence will be ##length(target) + 1## always. | |
810 | -- | |
811 | -- If ##x## is an atom this is the same as ##result = x & target##. If ##x## is | |
812 | -- a sequence it is not the same. | |
813 | -- | |
814 | -- The case where ##target## itself is prepend()ed to is handled very efficiently. | |
815 | -- | |
816 | -- Example 1: | |
817 | -- | |
818 | -- prepend({1,2,3}, {0,0}) -- {{0,0}, 1, 2, 3} | |
819 | -- -- Compare with concatenation: | |
820 | -- {0,0} & {1,2,3} -- {0, 0, 1, 2, 3} | |
821 | -- | |
822 | -- | |
823 | -- Example 2: | |
824 | -- | |
825 | -- s = {} | |
826 | -- for i = 1 to 10 do | |
827 | -- s = prepend(s, i) | |
828 | -- end for | |
829 | -- -- s is {10,9,8,7,6,5,4,3,2,1} | |
830 | -- | |
831 | -- | |
832 | -- See Also: | |
833 | -- [[:append]], [[:& -> amp_concat]] | |
834 | ||
835 | ||
836 | --**** | |
837 | -- Signature: | |
838 | -- | |
839 | -- | |
840 | -- Description: | |
841 | -- Insert an object into a sequence as a new element at a given location. | |
842 | -- | |
843 | -- Parameters: | |
844 | -- # ##target## : the sequence to insert into | |
845 | -- # ##what## : the object to insert | |
846 | -- # ##index## : an integer, the position in ##target## where ##what## | |
847 | -- should appear | |
848 | -- | |
849 | -- Returns: | |
850 | -- A **sequence**, which is ##target## with one more element at ##index##, | |
851 | -- which is ##what##. | |
852 | -- | |
853 | -- Comments: | |
854 | -- ##target## can be a sequence of any shape, and ##what## any kind of object. | |
855 | -- | |
856 | -- The length of the returned sequence is ##length(target)+1## always. | |
857 | -- | |
858 | -- insert()ing a sequence into a string returns a sequence which is no longer a string. | |
859 | -- | |
860 | -- Example 1: | |
861 | -- | |
862 | -- s = insert("John Doe", " Middle", 5) | |
863 | -- -- s is {'J','o','h','n'," Middle ",'D','o','e'} | |
864 | -- | |
865 | -- | |
866 | -- Example 2: | |
867 | -- | |
868 | -- s = insert({10,30,40}, 20, 2) | |
869 | -- -- s is {10,20,30,40} | |
870 | -- | |
871 | -- | |
872 | -- See Also: | |
873 | -- [[:remove]], [[:splice]], [[:append]], [[:prepend]] | |
874 | ||
875 | --**** | |
876 | -- Signature: | |
877 | -- | |
878 | -- | |
879 | -- Description: | |
880 | -- Inserts an object as a new slice in a sequence at a given position. | |
881 | -- | |
882 | -- Parameters: | |
883 | -- # ##target## : the sequence to insert into | |
884 | -- # ##what## : the object to insert | |
885 | -- # ##index## : an integer, the position in ##target## where ##what## should appear | |
886 | -- | |
887 | -- Returns: | |
888 | -- A **sequence**, which is ##target## with one or more elements, those of ##what##, | |
889 | -- inserted at locations starting at ##index##. | |
890 | -- | |
891 | -- Comments: | |
892 | -- ##target## can be a sequence of any shape, and ##what## any kind of object. | |
893 | -- | |
894 | -- The length of this new sequence is the sum of the lengths of ##target## and ##what## | |
895 | -- (atoms are of length 1 for this purpose). ##splice##() is equivalent to | |
896 | -- [[:insert]]() when ##what## is an atom, but not when it is a sequence. | |
897 | -- | |
898 | -- Splicing a string into a string results into a new string. | |
899 | -- | |
900 | -- Example 1: | |
901 | -- | |
902 | -- s = splice("John Doe", " Middle", 5) | |
903 | -- -- s is "John Middle Doe" | |
904 | -- | |
905 | -- | |
906 | -- Example 2: | |
907 | -- | |
908 | -- s = splice({10,30,40}, 20, 2) | |
909 | -- -- s is {10,20,30,40} | |
910 | -- | |
911 | -- | |
912 | -- See Also: | |
913 | -- [[:insert]], [[:remove]], [[:replace]], [[:& -> amp_concat]] | |
914 | ||
915 | --** | |
916 | -- Pad the beginning of a sequence with an object so as to meet a minimum | |
917 | -- length condition. | |
918 | -- | |
919 | -- Parameters: | |
920 | -- # ##target## : the sequence to pad. | |
921 | -- # ##size## : an integer, the target minimum size for ##target## | |
922 | -- # ##padding## : an object, usually the character to pad to (defaults to ' '). | |
923 | -- | |
924 | -- Returns: | |
925 | -- A **sequence**, either ##target## if it was long enough, or a sequence of | |
926 | -- length ##size## whose last elements are those of ##target## and whose first | |
927 | -- few head elements all equal ##padding##. | |
928 | -- | |
929 | -- Comments: | |
930 | -- ##pad_head##() will not remove characters. If ##length(target)## is greater | |
931 | -- than ##size##, this function simply returns ##target##. See [[:head]]() | |
932 | -- if you wish to truncate long sequences. | |
933 | -- | |
934 | -- Example 1: | |
935 | -- | |
936 | -- s = pad_head("ABC", 6) | |
937 | -- -- s is " ABC" | |
938 | -- | |
939 | -- s = pad_head("ABC", 6, '-') | |
940 | -- -- s is "---ABC" | |
941 | -- | |
942 | -- | |
943 | -- See Also: | |
944 | -- [[:trim_head]], [[:pad_tail]], [[:head]] | |
945 | ||
946 | 4 | |
947 | 4 | if size <= length(target) then |
948 | 2 | return target |
949 | end if | |
950 | ||
951 | 2 | return repeat(ch, size - length(target)) & target |
952 | end function | |
953 | ||
954 | --** | |
955 | -- Pad the end of a sequence with an object so as to meet a minimum length condition. | |
956 | -- | |
957 | -- Parameters: | |
958 | -- # ##target## : the sequence to pad. | |
959 | -- # ##size## : an integer, the target minimum size for ##target## | |
960 | -- # ##padding## : an object, usually the character to pad to (defaults to ' '). | |
961 | -- | |
962 | -- Returns: | |
963 | -- A **sequence**, either ##target## if it was long enough, or a sequence | |
964 | -- of length ##size## whose first elements are those of ##target## and whose | |
965 | -- last few head elements all equal ##padding##. | |
966 | -- | |
967 | -- Comments: | |
968 | -- ##pad_tail##() will not remove characters. If ##length(target)## is greater | |
969 | -- than ##size##, this function simply returns ##target##. See [[:tail]]() if | |
970 | -- you wish to truncate long sequences. | |
971 | -- | |
972 | -- Comments: | |
973 | -- | |
974 | -- ##pad_tail##() will not remove characters. If ##length(str)## is greater than params, this | |
975 | -- function simply returns str. see tail() if you wish to truncate long sequences. | |
976 | -- | |
977 | -- Example 1: | |
978 | -- | |
979 | -- s = pad_tail("ABC", 6) | |
980 | -- -- s is "ABC " | |
981 | -- | |
982 | -- s = pad_tail("ABC", 6, '-') | |
983 | -- -- s is "ABC---" | |
984 | -- | |
985 | -- | |
986 | -- See Also: | |
987 | -- [[:trim_tail]], [[:pad_head]], [[:tail]] | |
988 | ||
989 | 51 | |
990 | 51 | if size <= length(target) then |
991 | 2 | return target |
992 | end if | |
993 | ||
994 | 49 | return target & repeat(ch, size - length(target)) |
995 | end function | |
996 | ||
997 | --** | |
998 | -- Adds an item to the sequence if its not already there. If it already exists | |
999 | -- in the list, the list is returned unchanged. | |
1000 | -- | |
1001 | -- Parameters: | |
1002 | -- # ##needle## : object to add. | |
1003 | -- # ##haystack## : sequence to add it to. | |
1004 | -- # ##order## : an integer; determines how the ##needle## affects the ##haystack##. | |
1005 | -- It can be added to the front (prepended), to the back (appended), | |
1006 | -- or sorted after adding. The default is to prepend it. | |
1007 | -- | |
1008 | -- Returns: | |
1009 | -- A **sequence**, which is ##haystack## with ##needle## added to it. | |
1010 | -- | |
1011 | -- Comments: | |
1012 | -- | |
1013 | -- An error occurs if an invalid ##order## argument is supplied. | |
1014 | -- | |
1015 | -- The following enum is provided for specifying ##order##: | |
1016 | -- * ##ADD_PREPEND## ~-- prepend ##needle## to ##haystack##. This is the default option. | |
1017 | -- * ##ADD_APPEND## ~-- append ##needle## to ##haystack##. | |
1018 | -- * ##ADD_SORT_UP## ~-- sort ##haystack## in ascending order after inserting ##needle## | |
1019 | -- * ##ADD_SORT_DOWN## ~-- sort ##haystack## in descending order after inserting ##needle## | |
1020 | -- | |
1021 | -- Example 1: | |
1022 | -- | |
1023 | -- s = add_item( 1, {3,4,2}, ADD_PREPEND ) -- prepend | |
1024 | -- -- s is {1,3,4,2} | |
1025 | -- | |
1026 | -- | |
1027 | -- Example 2: | |
1028 | -- | |
1029 | -- s = add_item( 1, {3,4,2}, ADD_APPEND ) -- append | |
1030 | -- -- s is {3,4,2,1} | |
1031 | -- | |
1032 | -- | |
1033 | -- Example 3: | |
1034 | -- | |
1035 | -- s = add_item( 1, {3,4,2}, ADD_SORT_UP ) -- ascending | |
1036 | -- -- s is {1,2,3,4} | |
1037 | -- | |
1038 | -- | |
1039 | -- Example 4: | |
1040 | -- | |
1041 | -- s = add_item( 1, {3,4,2}, ADD_SORT_DOWN ) -- descending | |
1042 | -- -- s is {4,3,2,1} | |
1043 | -- | |
1044 | -- | |
1045 | -- Example 5: | |
1046 | -- | |
1047 | -- s = add_item( 1, {3,1,4,2} ) | |
1048 | -- -- s is {3,1,4,2} -- Item was already in list so no change. | |
1049 | -- | |
1050 | ||
1051 | 0 | |
1052 | 0 | if find(needle, haystack) then |
1053 | 0 | return haystack |
1054 | end if | |
1055 | 0 | switch pOrder do |
1056 | case ADD_PREPEND then | |
1057 | 0 | return prepend(haystack, needle) |
1058 | ||
1059 | case ADD_APPEND then | |
1060 | 0 | return append(haystack, needle) |
1061 | ||
1062 | case ADD_SORT_UP then | |
1063 | 0 | return sort(append(haystack, needle)) |
1064 | ||
1065 | case ADD_SORT_DOWN then | |
1066 | 0 | return sort(append(haystack, needle), DESCENDING) |
1067 | ||
1068 | case else | |
1069 | 0 | crash("sequence.e:add_item() invalid Order argument '%d'", pOrder) |
1070 | end switch | |
1071 | ||
1072 | 0 | return haystack |
1073 | end function | |
1074 | ||
1075 | --** | |
1076 | -- Removes an item from the sequence. | |
1077 | -- | |
1078 | -- Parameters: | |
1079 | -- # ##needle## : object to remove. | |
1080 | -- # ##haystack## : sequence to remove it from. | |
1081 | -- | |
1082 | -- Returns: | |
1083 | -- A **sequence**, which is ##haystack## with ##needle## removed from it. | |
1084 | -- | |
1085 | -- Comments: | |
1086 | -- If ##needle## is not in ##haystack## then ##haystack## is returned unchanged. | |
1087 | -- | |
1088 | -- Example 1: | |
1089 | -- | |
1090 | -- s = remove_item( 1, {3,4,2,1} ) --> {3,4,2} | |
1091 | -- s = remove_item( 5, {3,4,2,1} ) --> {3,4,2,1} | |
1092 | -- | |
1093 | ||
1094 | 4 | |
1095 | integer lIdx | |
1096 | ||
1097 | 4 | lIdx = find(needle, haystack) |
1098 | 4 | if not lIdx then |
1099 | 1 | return haystack |
1100 | end if | |
1101 | ||
1102 | 3 | if lIdx = 1 then |
1103 | 1 | return haystack[2 .. $] |
1104 | ||
1105 | 2 | elsif lIdx = length(haystack) then |
1106 | 1 | return haystack[1 .. $-1] |
1107 | ||
1108 | else | |
1109 | 1 | return haystack[1 .. lIdx - 1] & haystack[lIdx + 1 .. $] |
1110 | end if | |
1111 | end function | |
1112 | ||
1113 | --**** | |
1114 | -- === Extracting, removing, replacing from/into a sequence | |
1115 | -- | |
1116 | ||
1117 | --**** | |
1118 | -- Signature: | |
1119 | -- | |
1120 | -- | |
1121 | -- Description: | |
1122 | -- Return the first item(s) of a sequence. | |
1123 | -- | |
1124 | -- Parameters: | |
1125 | -- # ##source## : the sequence from which elements will be returned | |
1126 | -- # ##size## : an integer, how many head elements at most will be returned. | |
1127 | -- Defaults to 1. | |
1128 | -- | |
1129 | -- Returns: | |
1130 | -- A **sequence**, ##source## if its length is not greater than ##size##, | |
1131 | -- or the ##size## first elements of ##source## otherwise. | |
1132 | -- | |
1133 | -- Example 1: | |
1134 | -- | |
1135 | -- s2 = head("John Doe", 4) | |
1136 | -- -- s2 is John | |
1137 | -- | |
1138 | -- | |
1139 | -- Example 2: | |
1140 | -- | |
1141 | -- s2 = head("John Doe", 50) | |
1142 | -- -- s2 is John Doe | |
1143 | -- | |
1144 | -- | |
1145 | -- Example 3: | |
1146 | -- | |
1147 | -- s2 = head({1, 5.4, "John", 30}, 3) | |
1148 | -- -- s2 is {1, 5.4, "John"} | |
1149 | -- | |
1150 | -- | |
1151 | -- See Also: | |
1152 | -- [[:tail]], [[:mid]], [[:slice]] | |
1153 | ||
1154 | --**** | |
1155 | -- Signature: | |
1156 | -- | |
1157 | -- | |
1158 | -- Description: | |
1159 | -- Return the last items of a sequence. | |
1160 | -- | |
1161 | -- Parameters: | |
1162 | -- # ##source## : the sequence to get the tail of. | |
1163 | -- # ##size## : an integer, the number of items to return. | |
1164 | -- (defaults to length(source) - 1) | |
1165 | -- | |
1166 | -- Returns: | |
1167 | -- A **sequence**, of length at most ##size##. If the length is less than | |
1168 | -- ##size##, then ##source## was returned. Otherwise, the ##size## last elements | |
1169 | -- of ##source## were returned. | |
1170 | -- | |
1171 | -- Comments: | |
1172 | -- ##source## can be any type of sequence, including nested sequences. | |
1173 | -- | |
1174 | -- Example 1: | |
1175 | -- | |
1176 | -- s2 = tail("John Doe", 3) | |
1177 | -- -- s2 is "Doe" | |
1178 | -- | |
1179 | -- | |
1180 | -- Example 2: | |
1181 | -- | |
1182 | -- s2 = tail("John Doe", 50) | |
1183 | -- -- s2 is "John Doe" | |
1184 | -- | |
1185 | -- | |
1186 | -- Example 3: | |
1187 | -- | |
1188 | -- s2 = tail({1, 5.4, "John", 30}, 3) | |
1189 | -- -- s2 is {5.4, "John", 30} | |
1190 | -- | |
1191 | -- | |
1192 | -- See Also: | |
1193 | -- [[:head]], [[:mid]], [[:slice]] | |
1194 | ||
1195 | --** | |
1196 | -- Returns a slice of a sequence, given by a starting point and a length. | |
1197 | -- | |
1198 | -- Parameters: | |
1199 | -- # ##source## : the sequence some elements of which will be returned | |
1200 | -- # ##start## : an integer, the lower index of the slice to return | |
1201 | -- # ##len## : an integer, the length of the slice to return | |
1202 | -- | |
1203 | -- Returns: | |
1204 | -- A **sequence**, made of at most ##len## elements of ##source##. These | |
1205 | -- elements are at contiguous positions in ##source## starting at ##start##. | |
1206 | -- | |
1207 | -- Errors: | |
1208 | -- If ##len## is less than ##-length(source)##, an error occurs. | |
1209 | -- | |
1210 | -- Comments: | |
1211 | -- ##len## may be negative, in which case it is added ##length(source)## once. | |
1212 | -- | |
1213 | -- Example 1: | |
1214 | -- | |
1215 | -- s2 = mid("John Middle Doe", 6, 6) | |
1216 | -- -- s2 is Middle | |
1217 | -- | |
1218 | -- | |
1219 | -- Example 2: | |
1220 | -- | |
1221 | -- s2 = mid("John Middle Doe", 6, 50) | |
1222 | -- -- s2 is Middle Doe | |
1223 | -- | |
1224 | -- | |
1225 | -- Example 3: | |
1226 | -- | |
1227 | -- s2 = mid({1, 5.4, "John", 30}, 2, 2) | |
1228 | -- -- s2 is {5.4, "John"} | |
1229 | -- | |
1230 | -- | |
1231 | -- See Also: | |
1232 | -- [[:head]], [[:tail]], [[:slice]] | |
1233 | ||
1234 | 7 | |
1235 | 7 | if len<0 then |
1236 | 1 | len += length(source) |
1237 | 1 | if len<0 then |
1238 | 0 | crash("mid(): len was %d and should be greater than %d.", |
1239 | {len-length(source),-length(source)}) | |
1240 | end if | |
1241 | end if | |
1242 | 7 | if start > length(source) or len=0 then |
1243 | 1 | return "" |
1244 | end if | |
1245 | 6 | if start<1 then |
1246 | 1 | start=1 |
1247 | end if | |
1248 | 6 | if start+len-1 >= length(source) then |
1249 | 1 | return source[start..$] |
1250 | else | |
1251 | 5 | return source[start..len+start-1] |
1252 | end if | |
1253 | end function | |
1254 | ||
1255 | --** | |
1256 | -- Return a portion of the supplied sequence. | |
1257 | -- | |
1258 | -- Parameters: | |
1259 | -- # ##source## : the sequence from which to get a portion | |
1260 | -- # ##start## : an integer, the starting point of the portion. Default is 1. | |
1261 | -- # ##stop## : an integer, the ending point of the portion. Default is length(source). | |
1262 | -- | |
1263 | -- Returns: | |
1264 | -- A **sequence**. | |
1265 | -- | |
1266 | -- Comments: | |
1267 | -- * If the supplied ##start## is less than 1 then it set to 1. | |
1268 | -- * If the supplied ##stop## is less than 1 then ##length(source)## is added to it. | |
1269 | -- In this way, 0 represents the end of ##source##, -1 represents one element | |
1270 | -- in from the end of ##source## and so on. | |
1271 | -- * If the supplied ##stop## is greater than ##length(source)## then it is set to the end. | |
1272 | -- * After these adjustments, and if ##source[start..stop]## makes sense, it is | |
1273 | -- returned, otherwise, ##{}## is returned. | |
1274 | -- | |
1275 | -- Examples: | |
1276 | -- | |
1277 | -- s2 = slice("John Doe", 6, 8)--> "Doe" | |
1278 | -- s2 = slice("John Doe", 6, 50) --> "Doe" | |
1279 | -- s2 = slice({1, 5.4, "John", 30}, 2, 3) --> {5.4, "John"} | |
1280 | -- s2 = slice({1,2,3,4,5}, 2, -1) --> {2,3,4} | |
1281 | -- s2 = slice({1,2,3,4,5}, 2) --> {2,3,4,5} | |
1282 | -- s2 = slice({1,2,3,4,5}, , 4) --> {1,2,3,4} | |
1283 | -- | |
1284 | -- | |
1285 | -- See Also: | |
1286 | -- [[:head]], [[:mid]], [[:tail]] | |
1287 | ||
1288 | 10 | |
1289 | ||
1290 | 10 | if stop < 1 then |
1291 | 4 | stop += length(source) |
1292 | ||
1293 | 6 | elsif stop > length(source) then |
1294 | 1 | stop = length(source) |
1295 | ||
1296 | end if | |
1297 | ||
1298 | 10 | if start < 1 then |
1299 | 1 | start = 1 |
1300 | end if | |
1301 | ||
1302 | 10 | if start > stop then |
1303 | 1 | return "" |
1304 | end if | |
1305 | ||
1306 | 9 | return source[start..stop] |
1307 | end function | |
1308 | ||
1309 | --** | |
1310 | -- Perform a vertical slice on a nested sequence | |
1311 | -- | |
1312 | -- Parameters: | |
1313 | -- # ##source## : the sequence to take a vertical slice from | |
1314 | -- # ##colno## : an atom, the column number to extract (rounded down) | |
1315 | -- # ##error_control## : an object which says what to do if some element | |
1316 | -- does not exist. Defaults to 0 (crash in such a circumstance). | |
1317 | -- | |
1318 | -- Returns: | |
1319 | -- A **sequence**, usually of the same length as ##source##, made of all | |
1320 | -- the ##source[x][colno]##. | |
1321 | -- | |
1322 | -- Errors: | |
1323 | -- If an element is not defined and ##error_control## is 0, an error occurs. | |
1324 | -- If ##colno## is less than 1, it cannot be any valid column, and an error occurs. | |
1325 | -- | |
1326 | -- Comments: | |
1327 | -- If it is not possible to return the sequence of all ##source[x][colno]]## | |
1328 | -- for all available ##x##, the outcome is decided by ##error_control##: | |
1329 | -- * If 0 (the default), program is aborted. | |
1330 | -- * If a nonzero atom, the short vertical slice is returned. | |
1331 | -- * Otherwise, elements of ##error_control## will be taken to make for any | |
1332 | -- missing element. A short vertical slice is returned if ##error_control## is | |
1333 | -- exhausted. | |
1334 | -- | |
1335 | -- Example 1: | |
1336 | -- | |
1337 | -- s = vslice({{5,1}, {5,2}, {5,3}}, 2) | |
1338 | -- -- s is {1,2,3} | |
1339 | -- | |
1340 | -- s = vslice({{5,1}, {5,2}, {5,3}}, 1) | |
1341 | -- -- s is {5,5,5} | |
1342 | -- | |
1343 | -- | |
1344 | -- See Also: | |
1345 | -- [[:slice]], [[:project]] | |
1346 | ||
1347 | 5 | |
1348 | sequence ret | |
1349 | integer substitutes, current_sub | |
1350 | ||
1351 | 5 | if colno < 1 then |
1352 | 0 | crash("sequence:vslice(): colno should be a valid index, but was %d",colno) |
1353 | end if | |
1354 | ||
1355 | 5 | ret = source |
1356 | 5 | if atom(error_control) then |
1357 | 3 | substitutes =-(not error_control) |
1358 | else | |
1359 | 2 | substitutes = length(error_control) |
1360 | 2 | current_sub = 1 |
1361 | end if | |
1362 | ||
1363 | 5 | for i = 1 to length(source) do |
1364 | 14 | if colno >= 1+length(source[i]) then |
1365 | 2 | if substitutes=-1 then |
1366 | 0 | crash("sequence:vslice(): colno should be a valid index on the %d-th element, but was %d", {i,colno}) |
1367 | 2 | elsif substitutes=0 then |
1368 | 1 | return ret[1..i-1] |
1369 | else | |
1370 | 1 | substitutes -= 1 |
1371 | 1 | ret[i] = error_control[current_sub] |
1372 | 1 | current_sub += 1 |
1373 | end if | |
1374 | else | |
1375 | 12 | ret[i] = source[i][colno] |
1376 | end if | |
1377 | 13 | end for |
1378 | ||
1379 | 4 | return ret |
1380 | end function | |
1381 | ||
1382 | --**** | |
1383 | -- Signature: | |
1384 | -- | |
1385 | -- | |
1386 | -- Description: | |
1387 | -- Remove an item, or a range of items from a sequence. | |
1388 | -- | |
1389 | -- Parameters: | |
1390 | -- # ##target## : the sequence to remove from. | |
1391 | -- # ##start## : an atom, the (starting) index at which to remove | |
1392 | -- # ##stop## : an atom, the index at which to stop removing (defaults to ##start##) | |
1393 | -- | |
1394 | -- Returns: | |
1395 | -- A **sequence**, obtained from ##target## by carving the ##start..stop## slice | |
1396 | -- out of it. | |
1397 | -- | |
1398 | -- Comments: | |
1399 | -- A new sequence is created. ##target## can be a string or complex sequence. | |
1400 | -- | |
1401 | -- Example 1: | |
1402 | -- | |
1403 | -- s = remove("Johnn Doe", 4) | |
1404 | -- -- s is "John Doe" | |
1405 | -- | |
1406 | -- | |
1407 | -- Example 2: | |
1408 | -- | |
1409 | -- s = remove({1,2,3,3,4}, 4) | |
1410 | -- -- s is {1,2,3,4} | |
1411 | -- | |
1412 | -- | |
1413 | -- Example 3: | |
1414 | -- | |
1415 | -- s = remove("John Middle Doe", 6, 12) | |
1416 | -- -- s is "John Doe" | |
1417 | -- | |
1418 | -- | |
1419 | -- Example 4: | |
1420 | -- | |
1421 | -- s = remove({1,2,3,3,4,4}, 4, 5) | |
1422 | -- -- s is {1,2,3,4} | |
1423 | -- | |
1424 | -- | |
1425 | -- See Also: | |
1426 | -- [[:replace]], [[:insert]], [[:splice]], [[:remove_all]] | |
1427 | ||
1428 | ||
1429 | --** | |
1430 | -- Changes a sequence slice, possibly with padding | |
1431 | -- | |
1432 | -- Parameters: | |
1433 | -- # ##target## : a sequence, a modified copy of which will be returned | |
1434 | -- # ##source## : a sequence, to be patched inside or outside ##target## | |
1435 | -- # ##start## : an integer, the position at which to patch | |
1436 | -- # ##filler## : an object, used for filling gaps. Defaults to ' ' | |
1437 | -- | |
1438 | -- Returns: | |
1439 | -- A **sequence**, which looks like ##target##, but a slice starting at ##start## | |
1440 | -- equals ##source##. | |
1441 | -- | |
1442 | -- Comments: | |
1443 | -- | |
1444 | -- In some cases, this call will result in the same result as [[:replace]](). | |
1445 | -- | |
1446 | -- If ##source## doesn't fit into ##target## because of the lengths and the | |
1447 | -- supplied ##start## value, gaps will be created, and ##filler## is used to | |
1448 | -- fill them in. | |
1449 | -- | |
1450 | -- Notionally, ##target## has an infinite amount of ##filler## on both sides, | |
1451 | -- and ##start## counts position relative to where ##target## actually starts. | |
1452 | -- Then, notionally, a [[:replace]]() operation is performed. | |
1453 | -- | |
1454 | -- Example 1: | |
1455 | -- | |
1456 | -- sequence source = "abc", target = "John Doe" | |
1457 | -- sequence s = patch(target, source, 11,'0') | |
1458 | -- -- s is now "John Doe00abc" | |
1459 | -- | |
1460 | -- | |
1461 | -- Example 2: | |
1462 | -- | |
1463 | -- sequence source = "abc", target = "John Doe" | |
1464 | -- sequence s = patch(target, source, -1) | |
1465 | -- -- s is now "abcohn Doe" | |
1466 | -- Note that there was no gap to fill. | |
1467 | -- Since -1 = 1 - 2, the patching started 2 positions before the initial 'J'. | |
1468 | -- | |
1469 | -- | |
1470 | -- Example 3: | |
1471 | -- | |
1472 | -- sequence source = "abc", target = "John Doe" | |
1473 | -- sequence s = patch(target, source, 6) | |
1474 | -- -- s is now "John Dabc" | |
1475 | -- | |
1476 | -- | |
1477 | -- See Also: | |
1478 | -- [[:mid]], [[:replace]] | |
1479 | ||
1480 | 5 | |
1481 | 5 | if start + length(source) <= 0 then |
1482 | 0 | return source & repeat(filler, -start-length(source))+1 & target |
1483 | 5 | elsif start + length(source) <= length(target) then |
1484 | 2 | if start<=0 then |
1485 | 1 | return source & target[start+length(source)..$] |
1486 | else | |
1487 | 1 | return target[1..start-1] & source & target[start+length(source)..$] |
1488 | end if | |
1489 | 3 | elsif start <= 1 then |
1490 | 1 | return source |
1491 | 2 | elsif start <= length(target)+1 then |
1492 | 1 | return target[1..start-1] & source |
1493 | else | |
1494 | 1 | return target & repeat(filler,start-length(target)-1) & source |
1495 | end if | |
1496 | end function | |
1497 | ||
1498 | --** | |
1499 | -- Removes all occurrences of some object from a sequence. | |
1500 | -- | |
1501 | -- Parameters: | |
1502 | -- # ##needle## : the object to remove. | |
1503 | -- # ##haystack## : the sequence to remove from. | |
1504 | -- | |
1505 | -- Returns: | |
1506 | -- A **sequence**, of length at most ##length(haystack)##, and which has | |
1507 | -- the same elements, without any copy of ##needle## left | |
1508 | -- | |
1509 | -- Comments: | |
1510 | -- This function weeds elements out, not sub-sequences. | |
1511 | -- | |
1512 | -- Example 1: | |
1513 | -- | |
1514 | -- s = remove_all( 1, {1,2,4,1,3,2,4,1,2,3} ) | |
1515 | -- -- s is {2,4,3,2,4,2,3} | |
1516 | -- | |
1517 | -- | |
1518 | -- Example 2: | |
1519 | -- | |
1520 | -- s = remove_all('x', "I'm toox secxksy for my shixrt.") | |
1521 | -- -- s is "I'm too secksy for my shirt." | |
1522 | -- | |
1523 | -- | |
1524 | -- See Also: | |
1525 | -- [[:remove]], [[:replace]] | |
1526 | ||
1527 | 5 | |
1528 | integer ts, te, ss, se | |
1529 | ||
1530 | -- See if we have to do anything at all. | |
1531 | 5 | se = find(needle, haystack) |
1532 | 5 | if se = 0 then |
1533 | 2 | return haystack |
1534 | end if | |
1535 | ||
1536 | -- Now we know there is at least one occurrence and because | |
1537 | -- it's the first one, we don't have to move anything yet. | |
1538 | -- So pretend we have and set up the 'end' variables | |
1539 | -- as if we had moved stuff. | |
1540 | 3 | se -= 1 |
1541 | 3 | te = se |
1542 | ||
1543 | 3 | while se > 0 with entry do |
1544 | -- Shift elements down the sequence. | |
1545 | 10 | haystack[ts .. te] = haystack[ss .. se] |
1546 | ||
1547 | entry | |
1548 | -- Calc where the next target start is (1 after the previous end) | |
1549 | 13 | ts = te + 1 |
1550 | ||
1551 | -- Calc where to start the next search (2 after the previous end) | |
1552 | 13 | ss = se + 2 |
1553 | ||
1554 | -- See if we got another one. | |
1555 | 13 | se = find_from(needle, haystack, ss) |
1556 | ||
1557 | -- We have another one, so calculate the source end(1 before the needle) | |
1558 | 13 | se = se - 1 |
1559 | ||
1560 | -- Calc the target end (start + length of what we are moving) | |
1561 | 13 | te = ts + se - ss |
1562 | 13 | end while |
1563 | ||
1564 | -- Check to see if there is anything after the final needle | |
1565 | -- and move it. | |
1566 | 3 | if ss <= length(haystack) then |
1567 | 1 | te = ts + length(haystack) - ss |
1568 | 1 | haystack[ts .. te] = haystack[ss .. $] |
1569 | else | |
1570 | -- Need to backtrack one needle. | |
1571 | 2 | te = ts - 1 |
1572 | end if | |
1573 | ||
1574 | -- Return only the stuff we moved. | |
1575 | 3 | return haystack[1 .. te] |
1576 | end function | |
1577 | ||
1578 | --** | |
1579 | -- Keeps all occurrences of a set of objects from a sequence and removes all others. | |
1580 | -- | |
1581 | -- Parameters: | |
1582 | -- # ##needles## : the set of objects to retain. | |
1583 | -- # ##haystack## : the sequence to remove items not in ##needles##. | |
1584 | -- | |
1585 | -- Returns: | |
1586 | -- A **sequence** containing only those objects from ##haystack## that are also in ##needles##. | |
1587 | -- | |
1588 | -- Example: | |
1589 | -- | |
1590 | -- s = retain_all( {1,3,5}, {1,2,4,1,3,2,4,1,2,3} ) --> {1,1,3,1,3} | |
1591 | -- s = retain_all("0123456789", "+34 (04) 555-44392") -> "340455544392" | |
1592 | -- | |
1593 | -- | |
1594 | -- See Also: | |
1595 | -- [[:remove]], [[:replace]], [[:remove_all]] | |
1596 | ||
1597 | 5 | |
1598 | integer lp | |
1599 | integer np | |
1600 | sequence result | |
1601 | ||
1602 | 5 | if atom(needles) then |
1603 | 1 | needles = {needles} |
1604 | end if | |
1605 | 5 | if length(needles) = 0 then |
1606 | 1 | return {} |
1607 | end if | |
1608 | 4 | if length(haystack) = 0 then |
1609 | 1 | return {} |
1610 | end if | |
1611 | ||
1612 | 3 | result = haystack |
1613 | 3 | lp = length(haystack) |
1614 | 3 | np = 1 |
1615 | 3 | for i = 1 to length(haystack) do |
1616 | 30 | if find(haystack[i], needles) then |
1617 | 15 | if np < i then |
1618 | 4 | result[np .. lp] = haystack[i..$] |
1619 | end if | |
1620 | 15 | np += 1 |
1621 | else | |
1622 | 15 | lp -= 1 |
1623 | end if | |
1624 | 30 | end for |
1625 | ||
1626 | 3 | return result[1 .. lp] |
1627 | ||
1628 | end function | |
1629 | ||
1630 | --** | |
1631 | -- Filter a sequence based on a user supplied comparator function. | |
1632 | -- | |
1633 | -- Parameters: | |
1634 | -- * ##source## : sequence to filter | |
1635 | -- * ##rid## : Either a [[:routine_id]] of function to use as comparator or one | |
1636 | -- of the predefined comparitors. | |
1637 | -- * ##userdata## : an object passed to each invocation of ##rid##. If omitted, | |
1638 | -- {} is used. | |
1639 | -- * ##rangetype##: A sequence. Only used when ##rid## is "in" or "out". This is | |
1640 | -- used to let the function know how to interpret ##userdata##. When ##rangetype## | |
1641 | -- is an empty string (which is the default), then ##userdata## is treated as a set of zero or more | |
1642 | -- discrete items such that "in" will only return items from ##source## that are | |
1643 | -- in the set of item in ##userdata## and "out" returns those not in ##userdata##. | |
1644 | -- The other values for ##rangetype## mean that ##userdata## must be a set of | |
1645 | -- exactly two items, that represent the lower and upper limits of a range of | |
1646 | -- values. | |
1647 | -- | |
1648 | -- Returns: | |
1649 | -- A **sequence**, made of the elements in ##source## which passed the | |
1650 | -- comparitor test. | |
1651 | -- | |
1652 | -- Comments: | |
1653 | -- * The only items from ##source## that are returned are those that pass the test. | |
1654 | -- * When ##rid## is a routine_id, that user defined routine must be a function. | |
1655 | -- Each item in ##source##, along with the ##userdata## is passed to the function. | |
1656 | -- The function must return a non-zero atom if the item is to be included in the | |
1657 | -- result sequence, otherwise it should return zero to exclude it from the result. | |
1658 | -- * The predefined comparitors are... | |
1659 | -- | |
1660 | -- | "<" or "lt" | return items in ##source## that are less than ##userdata## | | |
1661 | -- | "<=" or "le" | return items in ##source## that are less than or equal to ##userdata## | | |
1662 | -- | "=" or "==" or "eq" | return items in ##source## that are equal to ##userdata## | | |
1663 | -- | "!=" or "ne" | return items in ##source## that are not equal to ##userdata## | | |
1664 | -- | ">" or "gt" | return items in ##source## that are greater than ##userdata## | | |
1665 | -- | ">=" or "ge" | return items in ##source## that are greater than or equal to ##userdata## | | |
1666 | -- | "in" | return items in ##source## that are in ##userdata## | | |
1667 | -- | "out" | return items in ##source## that are not in ##userdata## | | |
1668 | -- | |
1669 | -- * Range Type Usage | |
1670 | -- |= Range Type |= Meaning | | |
1671 | -- | "[]" | Inclusive range. Lower and upper are in the range. | | |
1672 | -- | "[)" | Low Inclusive range. Lower is in the range but upper is not. | | |
1673 | -- | "(]" | High Inclusive range. Lower is not in the range but upper is. | | |
1674 | -- | "()" | Exclusive range. Lower and upper are not in the range. | | |
1675 | -- | |
1676 | -- Example 1: | |
1677 | -- | |
1678 | -- function mask_nums(atom a, object t) | |
1679 | -- if sequence(t) then | |
1680 | -- return 0 | |
1681 | -- end if | |
1682 | -- return and_bits(a, t) != 0 | |
1683 | -- end function | |
1684 | -- | |
1685 | -- function even_nums(atom a, atom t) | |
1686 | -- return and_bits(a,1) = 0 | |
1687 | -- end function | |
1688 | -- | |
1689 | -- constant data = {5,8,20,19,3,2,10} | |
1690 | -- filter(data, routine_id("mask_nums"), 1) --> {5,19,3} | |
1691 | -- filter(data, routine_id("mask_nums"), 2) -->{19, 3, 2, 10} | |
1692 | -- filter(data, routine_id("even_nums")) -->{8, 20, 2, 10} | |
1693 | -- | |
1694 | -- -- Using 'in' and 'out' with sets. | |
1695 | -- filter(data, "in", {3,4,5,6,7,8}) -->{5,8,3} | |
1696 | -- filter(data, "out", {3,4,5,6,7,8}) -->{20,19,2,10} | |
1697 | -- | |
1698 | -- -- Using 'in' and 'out' with ranges. | |
1699 | -- filter(data, "in", {3,8}, "[]") --> {5,8,3} | |
1700 | -- filter(data, "in", {3,8}, "[)") --> {5,3} | |
1701 | -- filter(data, "in", {3,8}, "(]") --> {5,8} | |
1702 | -- filter(data, "in", {3,8}, "()") --> {5} | |
1703 | -- filter(data, "out", {3,8}, "[]") --> {20,19,2,10} | |
1704 | -- filter(data, "out", {3,8}, "[)") --> {8,20,19,2,10} | |
1705 | -- filter(data, "out", {3,8}, "(]") --> {20,19,3,2,10} | |
1706 | -- filter(data, "out", {3,8}, "()") --> {8,20,19,3,2,10} | |
1707 | -- | |
1708 | -- | |
1709 | -- Example 3: | |
1710 | -- | |
1711 | -- function quiksort(sequence s) | |
1712 | -- if length(s) < 2 then | |
1713 | -- return s | |
1714 | -- end if | |
1715 | -- return quiksort( filter(s[2..$], "<=", s[1]) ) & s[1] & quiksort(filter(s[2..$], ">", s[1])) | |
1716 | -- end function | |
1717 | -- ? quiksort( {5,4,7,2,4,9,1,0,4,32,7,54,2,5,8,445,67} ) | |
1718 | -- --> {0,1,2,2,4,4,4,5,5,7,7,8,9,32,54,67,445} | |
1719 | -- | |
1720 | -- | |
1721 | -- See Also: | |
1722 | -- [[:apply]] | |
1723 | ||
1724 | 50 | |
1725 | sequence dest | |
1726 | integer idx | |
1727 | ||
1728 | 50 | if length(source) = 0 then |
1729 | 1 | return source |
1730 | end if | |
1731 | 49 | dest = repeat(0, length(source)) |
1732 | 49 | idx = 0 |
1733 | 49 | switch rid do |
1734 | case "<", "lt" then | |
1735 | 2 | for a = 1 to length(source) do |
1736 | 14 | if compare(source[a], userdata) < 0 then |
1737 | 6 | idx += 1 |
1738 | 6 | dest[idx] = source[a] |
1739 | end if | |
1740 | 14 | end for |
1741 | ||
1742 | case "<=", "le" then | |
1743 | 12 | for a = 1 to length(source) do |
1744 | 63 | if compare(source[a], userdata) <= 0 then |
1745 | 30 | idx += 1 |
1746 | 30 | dest[idx] = source[a] |
1747 | end if | |
1748 | 63 | end for |
1749 | ||
1750 | case "=", "==", "eq" then | |
1751 | 3 | for a = 1 to length(source) do |
1752 | 21 | if compare(source[a], userdata) = 0 then |
1753 | 3 | idx += 1 |
1754 | 3 | dest[idx] = source[a] |
1755 | end if | |
1756 | 21 | end for |
1757 | ||
1758 | case "!=", "ne" then | |
1759 | 2 | for a = 1 to length(source) do |
1760 | 14 | if compare(source[a], userdata) != 0 then |
1761 | 12 | idx += 1 |
1762 | 12 | dest[idx] = source[a] |
1763 | end if | |
1764 | 14 | end for |
1765 | ||
1766 | case ">", "gt" then | |
1767 | 12 | for a = 1 to length(source) do |
1768 | 63 | if compare(source[a], userdata) > 0 then |
1769 | 33 | idx += 1 |
1770 | 33 | dest[idx] = source[a] |
1771 | end if | |
1772 | 63 | end for |
1773 | ||
1774 | case ">=", "ge" then | |
1775 | 2 | for a = 1 to length(source) do |
1776 | 14 | if compare(source[a], userdata) >= 0 then |
1777 | 8 | idx += 1 |
1778 | 8 | dest[idx] = source[a] |
1779 | end if | |
1780 | 14 | end for |
1781 | ||
1782 | case "in" then | |
1783 | 6 | switch rangetype do |
1784 | case "" then | |
1785 | 2 | for a = 1 to length(source) do |
1786 | 14 | if find(source[a], userdata) then |
1787 | 6 | idx += 1 |
1788 | 6 | dest[idx] = source[a] |
1789 | end if | |
1790 | 14 | end for |
1791 | ||
1792 | case "[]" then | |
1793 | 1 | for a = 1 to length(source) do |
1794 | 7 | if compare(source[a], userdata[1]) >= 0 then |
1795 | 6 | if compare(source[a], userdata[2]) <= 0 then |
1796 | 3 | idx += 1 |
1797 | 3 | dest[idx] = source[a] |
1798 | end if | |
1799 | end if | |
1800 | 7 | end for |
1801 | ||
1802 | case "[)" then | |
1803 | 1 | for a = 1 to length(source) do |
1804 | 7 | if compare(source[a], userdata[1]) >= 0 then |
1805 | 6 | if compare(source[a], userdata[2]) < 0 then |
1806 | 2 | idx += 1 |
1807 | 2 | dest[idx] = source[a] |
1808 | end if | |
1809 | end if | |
1810 | 7 | end for |
1811 | case "(]" then | |
1812 | 1 | for a = 1 to length(source) do |
1813 | 7 | if compare(source[a], userdata[1]) > 0 then |
1814 | 5 | if compare(source[a], userdata[2]) <= 0 then |
1815 | 2 | idx += 1 |
1816 | 2 | dest[idx] = source[a] |
1817 | end if | |
1818 | end if | |
1819 | 7 | end for |
1820 | case "()" then | |
1821 | 1 | for a = 1 to length(source) do |
1822 | 7 | if compare(source[a], userdata[1]) > 0 then |
1823 | 5 | if compare(source[a], userdata[2]) < 0 then |
1824 | 1 | idx += 1 |
1825 | 1 | dest[idx] = source[a] |
1826 | end if | |
1827 | end if | |
1828 | 7 | end for |
1829 | ||
1830 | end switch | |
1831 | ||
1832 | case "out" then | |
1833 | 6 | switch rangetype do |
1834 | case "" then | |
1835 | 2 | for a = 1 to length(source) do |
1836 | 14 | if not find(source[a], userdata) then |
1837 | 8 | idx += 1 |
1838 | 8 | dest[idx] = source[a] |
1839 | end if | |
1840 | 14 | end for |
1841 | ||
1842 | case "[]" then | |
1843 | 1 | for a = 1 to length(source) do |
1844 | 7 | if compare(source[a], userdata[1]) < 0 then |
1845 | 1 | idx += 1 |
1846 | 1 | dest[idx] = source[a] |
1847 | 6 | elsif compare(source[a], userdata[2]) > 0 then |
1848 | 3 | idx += 1 |
1849 | 3 | dest[idx] = source[a] |
1850 | end if | |
1851 | 7 | end for |
1852 | ||
1853 | case "[)" then | |
1854 | 1 | for a = 1 to length(source) do |
1855 | 7 | if compare(source[a], userdata[1]) < 0 then |
1856 | 1 | idx += 1 |
1857 | 1 | dest[idx] = source[a] |
1858 | 6 | elsif compare(source[a], userdata[2]) >= 0 then |
1859 | 4 | idx += 1 |
1860 | 4 | dest[idx] = source[a] |
1861 | end if | |
1862 | 7 | end for |
1863 | case "(]" then | |
1864 | 1 | for a = 1 to length(source) do |
1865 | 7 | if compare(source[a], userdata[1]) <= 0 then |
1866 | 2 | idx += 1 |
1867 | 2 | dest[idx] = source[a] |
1868 | 5 | elsif compare(source[a], userdata[2]) > 0 then |
1869 | 3 | idx += 1 |
1870 | 3 | dest[idx] = source[a] |
1871 | end if | |
1872 | 7 | end for |
1873 | case "()" then | |
1874 | 1 | for a = 1 to length(source) do |
1875 | 7 | if compare(source[a], userdata[1]) <= 0 then |
1876 | 2 | idx += 1 |
1877 | 2 | dest[idx] = source[a] |
1878 | 5 | elsif compare(source[a], userdata[2]) >= 0 then |
1879 | 4 | idx += 1 |
1880 | 4 | dest[idx] = source[a] |
1881 | end if | |
1882 | 7 | end for |
1883 | ||
1884 | end switch | |
1885 | ||
1886 | case else | |
1887 | 4 | for a = 1 to length(source) do |
1888 | 30 | if call_func(rid, {source[a], userdata}) then |
1889 | 14 | idx += 1 |
1890 | 14 | dest[idx] = source[a] |
1891 | end if | |
1892 | 30 | end for |
1893 | end switch | |
1894 | 49 | return dest[1..idx] |
1895 | end function | |
1896 | ||
1897 | 9 | |
1898 | 9 | return t_alpha(elem) |
1899 | end function | |
1900 | ||
1901 | --** | |
1902 | -- Signature: | |
1903 | -- public constant STDFLTR_ALPHA | |
1904 | -- | |
1905 | -- Description: | |
1906 | -- Predefined routine_id for use with [[:filter]](). | |
1907 | -- | |
1908 | -- Comments: | |
1909 | -- Used to filter out non-alphabetic characters from a string. | |
1910 | -- | |
1911 | -- Example: | |
1912 | -- | |
1913 | -- -- Collect only the alphabetic characters from 'text' | |
1914 | -- result = filter(text, STDFLTR_ALPHA) | |
1915 | -- | |
1916 | -- | |
1917 | ||
1918 | 101 | public constant STDFLTR_ALPHA = routine_id("filter_alpha") |
1919 | ||
1920 | --**** | |
1921 | -- Signature: | |
1922 | -- | |
1923 | -- | |
1924 | -- Description: | |
1925 | -- Replace a slice in a sequence by an object. | |
1926 | -- | |
1927 | -- Parameters: | |
1928 | -- # ##target## : the sequence in which replacement will be done. | |
1929 | -- # ##replacement## : an object, the item to replace with. | |
1930 | -- # ##start## : an integer, the starting index of the slice to replace. | |
1931 | -- # ##stop## : an integer, the stopping index of the slice to replace. | |
1932 | -- | |
1933 | -- Returns: | |
1934 | -- A **sequence**, which is made of ##target## with the ##start..stop## slice | |
1935 | -- removed and replaced by ##replacement##, which is [[:splice]]()d in. | |
1936 | -- | |
1937 | -- Comments: | |
1938 | -- * A new sequence is created. ##target## can be a string or complex sequence | |
1939 | -- of any shape. | |
1940 | -- | |
1941 | -- * To replace by just one element, enclose ##replacement## in curly braces, | |
1942 | -- which will be removed at replace time. | |
1943 | -- | |
1944 | -- Example 1: | |
1945 | -- | |
1946 | -- s = replace("John Middle Doe", "Smith", 6, 11) | |
1947 | -- -- s is "John Smith Doe" | |
1948 | -- | |
1949 | -- s = replace({45.3, "John", 5, {10, 20}}, 25, 2, 3) | |
1950 | -- -- s is {45.3, 25, {10, 20}} | |
1951 | -- | |
1952 | -- | |
1953 | -- See Also: | |
1954 | -- [[:splice]], [[:remove]], [[:remove_all]] | |
1955 | ||
1956 | --** | |
1957 | -- Description: | |
1958 | -- Replaces all occurrences of ##olddata## with ##newdata## | |
1959 | -- | |
1960 | -- Parameters: | |
1961 | -- # ##source## : the sequence in which replacements will be done. | |
1962 | -- # ##olddata## : the sequence/item which is going to be replaced. If this | |
1963 | -- is an empty sequence, the ##source## is returned as is. | |
1964 | -- # ##newdata## : the sequence/item which will be the replacement. | |
1965 | -- | |
1966 | -- Returns: | |
1967 | -- A **sequence**, which is made of ##source## with all ##olddata## occurrences | |
1968 | -- replaced by ##newdata##. | |
1969 | -- | |
1970 | -- Comments: | |
1971 | -- This also removes all ##olddata## occurrences when ##newdata## is "". | |
1972 | -- | |
1973 | -- Example: | |
1974 | -- | |
1975 | -- s = replace_all("abracadabra", 'a', 'X') | |
1976 | -- -- s is now "XbrXcXdXbrX" | |
1977 | -- s = replace_all("abracadabra", "ra", 'X') | |
1978 | -- -- s is now "abXcadabX" | |
1979 | -- s = replace_all("abracadabra", "a", "aa") | |
1980 | -- -- s is now "aabraacaadaabraa" | |
1981 | -- s = replace_all("abracadabra", "a", "") | |
1982 | -- -- s is now "brcdbr" | |
1983 | -- | |
1984 | -- | |
1985 | -- See Also: | |
1986 | -- [[:replace]], [[:remove_all]] | |
1987 | ||
1988 | 49 | |
1989 | integer startpos | |
1990 | integer endpos | |
1991 | ||
1992 | 49 | if atom(olddata) then |
1993 | 2 | olddata = {olddata} |
1994 | end if | |
1995 | ||
1996 | 49 | if atom(newdata) then |
1997 | 2 | newdata = {newdata} |
1998 | end if | |
1999 | ||
2000 | 49 | if length(olddata) = 0 then |
2001 | 1 | return source |
2002 | end if | |
2003 | ||
2004 | 48 | endpos = 1 |
2005 | 48 | while startpos != 0 with entry do |
2006 | 97 | endpos = startpos + length(olddata) - 1 |
2007 | 97 | source = replace(source, newdata, startpos, endpos) |
2008 | 97 | endpos = startpos + length(newdata) |
2009 | entry | |
2010 | 145 | startpos = match_from(olddata, source, endpos) |
2011 | 145 | end while |
2012 | ||
2013 | 48 | return source |
2014 | end function | |
2015 | ||
2016 | --** | |
2017 | -- Turns a sequences of indexes into the sequence of elements in a source that have such indexes. | |
2018 | -- | |
2019 | -- Parameters: | |
2020 | -- # ##source## : the sequence from which to extract elements | |
2021 | -- # ##indexes## : a sequence of atoms, the indexes of the elements to be fetched in ##source##. | |
2022 | -- | |
2023 | -- Returns: | |
2024 | -- A **sequence**, of length at most ##length(indexes)##. If ##p## is the r-th element of ##indexes## which is valid on ##source##, then ##result[r]## is ##source[p]##. | |
2025 | -- | |
2026 | -- Example 1: | |
2027 | -- | |
2028 | -- s = extract({11,13,15,17},{3,1,2,1,4}) | |
2029 | -- -- s is {15,11,13,11,17} | |
2030 | -- | |
2031 | -- | |
2032 | -- See Also: | |
2033 | -- [[:slice]] | |
2034 | ||
2035 | 22 | |
2036 | object p | |
2037 | ||
2038 | 22 | for i = 1 to length(indexes) do |
2039 | 48 | p = indexes[i] |
2040 | 48 | if not valid_index(source,p) then |
2041 | 0 | crash("%d is not a valid index on the input sequence",p) |
2042 | end if | |
2043 | 48 | indexes[i] = source[p] |
2044 | 48 | end for |
2045 | 22 | return indexes |
2046 | end function | |
2047 | ||
2048 | --** | |
2049 | -- Creates a list of sequences based on selected elements from sequences in the source. | |
2050 | -- | |
2051 | -- Parameters: | |
2052 | -- # ##source## : a list of sequences. | |
2053 | -- # ##coords## : a list of index lists. | |
2054 | -- | |
2055 | -- Returns: | |
2056 | -- A **sequence**, with the same length as ##source##. Each of its elements is a sequence, | |
2057 | -- the length of ##coords##. Each innermost sequence is made of the | |
2058 | -- elements from the corresponding source sub-sequence. | |
2059 | -- | |
2060 | -- Comments: | |
2061 | -- For each sequence in ##source##, a set of sub-sequences is created; one for | |
2062 | -- each index list in ##coords##. An index list is just a sequence containing | |
2063 | -- indexes for items in a sequence. | |
2064 | -- | |
2065 | -- Example 1: | |
2066 | -- | |
2067 | -- s = project({ "ABCD", "789"}, {{1,2}, {3,1}, {2}}) | |
2068 | -- -- s is {{"AB","CA","B"},{"78","97","8"}} | |
2069 | -- | |
2070 | -- | |
2071 | -- See Also: | |
2072 | -- [[:vslice]], [[:extract]] | |
2073 | ||
2074 | 2 | |
2075 | sequence result | |
2076 | ||
2077 | 2 | result = repeat( repeat(0, length(coords)), length(source) ) |
2078 | 2 | for i = 1 to length(source) do |
2079 | 7 | for j = 1 to length(coords) do |
2080 | 18 | result[i][j] = extract(source[i], coords[j]) |
2081 | 18 | end for |
2082 | 7 | end for |
2083 | 2 | return result |
2084 | end function | |
2085 | ||
2086 | --**** | |
2087 | -- === Changing the shape of a sequence | |
2088 | -- | |
2089 | ||
2090 | --** | |
2091 | -- Split a sequence on separator delimiters into a number of sub-sequences. | |
2092 | -- | |
2093 | -- Parameters: | |
2094 | -- # ##delim## : an object (default is ' '). The delimiter that separates items | |
2095 | -- in ##source##. | |
2096 | -- # ##source## : the sequence to split. | |
2097 | -- # ##limit## : an integer (default is 0). The maximum number of sub-sequences | |
2098 | -- to create. If zero, there is no limit. | |
2099 | -- # ##no_empty## : an integer (default is 0). If not zero then all zero-length sub-sequences | |
2100 | -- are removed from the returned sequence. Use this when leading, | |
2101 | -- trailing and duplicated delimiters are not significant. | |
2102 | -- | |
2103 | -- Returns: | |
2104 | -- A **sequence**, of sub-sequences of ##source##. Delimiters are removed. | |
2105 | -- | |
2106 | -- Comments: | |
2107 | -- This function may be applied to a string sequence or a complex sequence. | |
2108 | -- | |
2109 | -- If ##limit## is > 0, this is the maximum number of sub-sequences that will | |
2110 | -- created, otherwise there is no limit. | |
2111 | -- | |
2112 | -- Example 1: | |
2113 | -- | |
2114 | -- result = split(,"John Middle Doe") | |
2115 | -- -- result is {"John", "Middle", "Doe"} | |
2116 | -- | |
2117 | -- | |
2118 | -- Example 2: | |
2119 | -- | |
2120 | -- result = split(",", "John,Middle,Doe", 2) | |
2121 | -- -- result is {"John", "Middle,Doe"} | |
2122 | -- | |
2123 | -- | |
2124 | -- See Also: | |
2125 | -- [[:split_any]], [[:breakup]], [[:join]] | |
2126 | ||
2127 | 25 | |
2128 | 25 | sequence ret = {} |
2129 | integer start | |
2130 | integer pos | |
2131 | ||
2132 | 25 | if length(st) = 0 then |
2133 | 1 | return ret |
2134 | end if | |
2135 | ||
2136 | ||
2137 | 24 | if sequence(delim) then |
2138 | -- Handle the simple case of split("", "123"), opposite is join({"1","2","3"}, "") -- "123" | |
2139 | 4 | if equal(delim, "") then |
2140 | 2 | for i = 1 to length(st) do |
2141 | 4 | st[i] = {st[i]} |
2142 | 4 | limit -= 1 |
2143 | 4 | if limit = 0 then |
2144 | 1 | st = append(st[1 .. i],st[i+1 .. $]) |
2145 | 1 | exit |
2146 | end if | |
2147 | 3 | end for |
2148 | ||
2149 | 2 | return st |
2150 | end if | |
2151 | ||
2152 | 2 | start = 1 |
2153 | 2 | while start <= length(st) do |
2154 | 5 | pos = match_from(delim, st, start) |
2155 | ||
2156 | 5 | if pos = 0 then |
2157 | 1 | exit |
2158 | end if | |
2159 | ||
2160 | 4 | ret = append(ret, st[start..pos-1]) |
2161 | 4 | start = pos+length(delim) |
2162 | 4 | limit -= 1 |
2163 | 4 | if limit = 0 then |
2164 | 0 | exit |
2165 | end if | |
2166 | 4 | end while |
2167 | else | |
2168 | 20 | start = 1 |
2169 | 20 | while start <= length(st) do |
2170 | 71 | pos = find_from(delim, st, start) |
2171 | ||
2172 | 71 | if pos = 0 then |
2173 | 16 | exit |
2174 | end if | |
2175 | ||
2176 | 55 | ret = append(ret, st[start..pos-1]) |
2177 | 55 | start = pos + 1 |
2178 | 55 | limit -= 1 |
2179 | 55 | if limit = 0 then |
2180 | 1 | exit |
2181 | end if | |
2182 | 54 | end while |
2183 | end if | |
2184 | ||
2185 | 22 | ret = append(ret, st[start..$]) |
2186 | ||
2187 | 22 | integer k = length(ret) |
2188 | 22 | if no_empty then |
2189 | 2 | k = 0 |
2190 | 2 | for i = 1 to length(ret) do |
2191 | 10 | if length(ret[i]) != 0 then |
2192 | 5 | k += 1 |
2193 | 5 | if k != i then |
2194 | 3 | ret[k] = ret[i] |
2195 | end if | |
2196 | end if | |
2197 | 10 | end for |
2198 | end if | |
2199 | ||
2200 | 22 | if k < length(ret) then |
2201 | 1 | return ret[1 .. k] |
2202 | else | |
2203 | 21 | return ret |
2204 | end if | |
2205 | end function | |
2206 | ||
2207 | --** | |
2208 | -- Split a sequence by any of the separators in the list of delimiters. | |
2209 | -- | |
2210 | -- If limit is > 0 then limit the number of tokens that will be split to limit. | |
2211 | -- | |
2212 | -- Parameters: | |
2213 | -- # ##source## : the sequence to split. | |
2214 | -- # ##delim## : a list of delimiters to split by. | |
2215 | -- # ##limit## : an integer (default is 0). The maximum number of sub-sequences | |
2216 | -- to create. If zero, there is no limit. | |
2217 | -- # ##no_empty## : an integer (default is 0). If not zero then all zero-length sub-sequences | |
2218 | -- removed from the returned sequence. Use this when leading, | |
2219 | -- trailing and duplicated delimiters are not significant. | |
2220 | -- | |
2221 | -- Comments: | |
2222 | -- This function may be applied to a string sequence or a complex sequence. | |
2223 | -- | |
2224 | -- It works like ##split##(), but in this case ##delim## is a set of potential | |
2225 | -- delimiters rather than a single delimiter. | |
2226 | -- | |
2227 | -- Example 1: | |
2228 | -- | |
2229 | -- result = split_any("One,Two|Three.Four", ".,|") | |
2230 | -- -- result is {"One", "Two", "Three", "Four"} | |
2231 | -- result = split_any(",One,,Two|.Three||.Four,", ".,|",,1) -- No Empty option | |
2232 | -- -- result is {"One", "Two", "Three", "Four"} | |
2233 | -- | |
2234 | -- | |
2235 | -- See Also: | |
2236 | -- [[:split]], [[:breakup]], [[:join]] | |
2237 | ||
2238 | 4 | |
2239 | 4 | sequence ret = {} |
2240 | 4 | integer start = 1, pos, next_pos |
2241 | ||
2242 | 4 | if atom(delim) then |
2243 | 1 | delim = {delim} |
2244 | end if | |
2245 | ||
2246 | 4 | if length(delim) = 0 then |
2247 | 0 | crash("sequence:split_any(): delimiter length must be greater than 0") |
2248 | end if | |
2249 | ||
2250 | 4 | while 1 do |
2251 | 15 | pos = find_any(delim, source, start) |
2252 | 15 | next_pos = pos + 1 |
2253 | 15 | if pos then |
2254 | 12 | ret = append(ret, source[start..pos-1]) |
2255 | 12 | start = next_pos |
2256 | 12 | limit -= 1 |
2257 | 12 | if limit = 0 then |
2258 | 1 | exit |
2259 | end if | |
2260 | else | |
2261 | 3 | exit |
2262 | end if | |
2263 | 11 | end while |
2264 | ||
2265 | 4 | ret = append(ret, source[start..$]) |
2266 | ||
2267 | 4 | integer k = length(ret) |
2268 | 4 | if no_empty then |
2269 | 1 | k = 0 |
2270 | 1 | for i = 1 to length(ret) do |
2271 | 8 | if length(ret[i]) != 0 then |
2272 | 3 | k += 1 |
2273 | 3 | if k != i then |
2274 | 3 | ret[k] = ret[i] |
2275 | end if | |
2276 | end if | |
2277 | 8 | end for |
2278 | end if | |
2279 | ||
2280 | 4 | if k < length(ret) then |
2281 | 1 | return ret[1 .. k] |
2282 | else | |
2283 | 3 | return ret |
2284 | end if | |
2285 | end function | |
2286 | ||
2287 | --** | |
2288 | -- Join sequences together using a delimiter. | |
2289 | -- | |
2290 | -- Parameters: | |
2291 | -- # ##items## : the sequence of items to join. | |
2292 | -- # ##delim## : an object, the delimiter to join by. Defaults to " ". | |
2293 | -- | |
2294 | -- Comments: | |
2295 | -- This function may be applied to a string sequence or a complex sequence | |
2296 | -- | |
2297 | -- Example 1: | |
2298 | -- | |
2299 | -- result = join({"John", "Middle", "Doe"}) | |
2300 | -- -- result is "John Middle Doe" | |
2301 | -- | |
2302 | -- | |
2303 | -- Example 2: | |
2304 | -- | |
2305 | -- result = join({"John", "Middle", "Doe"}, ",") | |
2306 | -- -- result is "John,Middle,Doe" | |
2307 | -- | |
2308 | -- | |
2309 | -- See Also: | |
2310 | -- [[:split]], [[:split_any]], [[:breakup]] | |
2311 | ||
2312 | 5 | |
2313 | object ret | |
2314 | ||
2315 | 5 | if not length(items) then return {} end if |
2316 | ||
2317 | 5 | ret = {} |
2318 | 5 | for i=1 to length(items)-1 do |
2319 | 9 | ret &= items[i] & delim |
2320 | 9 | end for |
2321 | ||
2322 | 5 | ret &= items[$] |
2323 | ||
2324 | 5 | return ret |
2325 | end function | |
2326 | ||
2327 | -- Style options for breakup() | |
2328 | ||
2329 | public enum | |
2330 | --** Indicates that ##size## parameter is maximum length of sub-sequence. See [[:breakup]] | |
2331 | 101 | BK_LEN, |
2332 | --** Indicates that ##size## parameter is maximum number of sub-sequence. See [[:breakup]] | |
2333 | 101 | BK_PIECES |
2334 | ||
2335 | --** | |
2336 | -- Breaks up a sequence into multiple sequences of a given length. | |
2337 | -- | |
2338 | -- Parameters: | |
2339 | -- # ##source## : the sequence to be broken up into sub-sequences. | |
2340 | -- # ##size## : an object, if an integer it is either the maximum length of | |
2341 | -- each resulting sub-sequence or the maximum number of | |
2342 | -- sub-sequences to break ##source## into. \\ | |
2343 | -- If ##size## is a sequence, it is a list of element counts | |
2344 | -- for the sub-sequences it creates. | |
2345 | -- # ##style## : an integer, Either BK_LEN if ##size## integer represents | |
2346 | -- the sub-sequences' maximum length, or BK_PIECES if | |
2347 | -- the ##size## integer represents the maximum number of | |
2348 | -- sub-sequences (pieces) to break ##source## into. | |
2349 | -- | |
2350 | -- Returns: | |
2351 | -- A **sequence**, of sequences. | |
2352 | -- | |
2353 | -- Comments: | |
2354 | -- **When ##size## is an integer and ##style## is BK_LEN...**\\ | |
2355 | -- The sub-sequences have length ##size##, except possibly the last one, | |
2356 | -- which may be shorter. For example if ##source## has 11 items and ##size## is | |
2357 | -- 3, then the first three sub-sequences will get 3 items each and the remaining | |
2358 | -- 2 items will go into the last sub-sequence. If ##size## is less than 1 or | |
2359 | -- greater than the length of the ##source##, the ##source## is returned as the | |
2360 | -- only sub-sequence. | |
2361 | -- | |
2362 | -- **When ##size## is an integer and ##style## is BK_PIECES...**\\ | |
2363 | -- There is exactly ##size## sub-sequences created. If the ##source## is not | |
2364 | -- evenly divisible into that many pieces, then the lefthand sub-sequences will | |
2365 | -- contain one more element than the right-hand sub-sequences. For example, if | |
2366 | -- source contains 10 items and we break it into 3 pieces, piece #1 gets 4 elements, | |
2367 | -- piece #2 gets 3 items and piece #3 gets 3 items - a total of 10. If source had | |
2368 | -- 11 elements then the pieces will have 4,4, and 3 respectively. | |
2369 | -- | |
2370 | -- **When ##size## is a sequence...**\\ | |
2371 | -- The style parameter is ignored in this case. The source will be broken up | |
2372 | -- according to the counts contained in the size parameter. For example, if | |
2373 | -- ##size## was {3,4,0,1} then piece #1 gets 3 items, #2 gets 4 items, #3 gets | |
2374 | -- 0 items, and #4 gets 1 item. Note that if not all items from source are | |
2375 | -- placed into the sub-sequences defined by ##size##, and //extra// sub-sequence | |
2376 | -- is appended that contains the remaining items from ##source##. | |
2377 | -- | |
2378 | -- In all cases, when concatenated these sub-sequences will be identical | |
2379 | -- to the original ##source##. | |
2380 | -- | |
2381 | -- | |
2382 | -- Example 1: | |
2383 | -- | |
2384 | -- s = breakup("5545112133234454", 4) | |
2385 | -- -- s is {"5545", "1121", "3323", "4454"} | |
2386 | -- | |
2387 | -- | |
2388 | -- Example 2: | |
2389 | -- | |
2390 | -- s = breakup("12345", 2) | |
2391 | -- -- s is {"12", "34", "5"} | |
2392 | -- | |
2393 | -- | |
2394 | -- Example 3: | |
2395 | -- | |
2396 | -- s = breakup({1,2,3,4,5,6}, 3) | |
2397 | -- -- s is {{1,2,3}, {4,5,6}} | |
2398 | -- | |
2399 | -- | |
2400 | -- Example 4: | |
2401 | -- | |
2402 | -- s = breakup("ABCDEF", 0) | |
2403 | -- -- s is {"ABCDEF"} | |
2404 | -- | |
2405 | -- | |
2406 | -- See Also: | |
2407 | -- [[:split]] [[:flatten]] | |
2408 | ||
2409 | 22 | |
2410 | ||
2411 | 22 | if atom(size) and not integer(size) then |
2412 | 0 | size = floor(size) |
2413 | end if | |
2414 | ||
2415 | -- Convert simple integer size into the 'customized' size format. | |
2416 | 22 | if integer(size) then |
2417 | 14 | integer len |
2418 | 14 | integer rem |
2419 | 14 | if style = BK_LEN then |
2420 | 6 | if size < 1 or size >= length(source) then |
2421 | 3 | return {source} |
2422 | end if | |
2423 | 3 | len = floor(length(source) / size) |
2424 | 3 | rem = remainder(length(source), size) |
2425 | 3 | size = repeat(size, len) |
2426 | 3 | if rem > 0 then |
2427 | 1 | size &= rem |
2428 | end if | |
2429 | else | |
2430 | 8 | if size > length(source) then |
2431 | 2 | size = length(source) |
2432 | end if | |
2433 | 8 | if size < 1 then |
2434 | 2 | return {source} |
2435 | end if | |
2436 | 6 | len = floor(length(source) / size) |
2437 | 6 | if len < 1 then |
2438 | 0 | len = 1 |
2439 | end if | |
2440 | 6 | rem = length(source) - (size * len) |
2441 | 6 | size = repeat(len, size) |
2442 | 6 | for i = 1 to length(size) do |
2443 | 10 | if rem = 0 then |
2444 | 6 | exit |
2445 | end if | |
2446 | 4 | size[i] += 1 |
2447 | 4 | rem -= 1 |
2448 | 4 | end for |
2449 | end if | |
2450 | end if | |
2451 | ||
2452 | ||
2453 | -- Allocate the top level sequence. | |
2454 | 17 | sequence ns = repeat(0, length(size)) |
2455 | 17 | integer source_idx = 1 |
2456 | ||
2457 | -- Place each source element into its appropriate target sub-sequence. | |
2458 | 17 | for i = 1 to length(size) do |
2459 | 42 | if source_idx <= length(source) then |
2460 | 40 | integer k = 1 |
2461 | 40 | ns[i] = repeat(0, size[i]) |
2462 | 40 | for j = 1 to size[i] do |
2463 | 90 | if source_idx > length(source) then |
2464 | 1 | ns[i] = ns[i][1 .. k-1] |
2465 | 1 | exit |
2466 | end if | |
2467 | 89 | ns[i][k] = source[source_idx] |
2468 | 89 | k += 1 |
2469 | 89 | source_idx += 1 |
2470 | 89 | end for |
2471 | else | |
2472 | 2 | ns[i] = {} |
2473 | end if | |
2474 | 42 | end for |
2475 | ||
2476 | --Handle any leftover data from source. | |
2477 | 17 | if source_idx <= length(source) then |
2478 | 4 | ns = append(ns, source[source_idx .. $]) |
2479 | end if | |
2480 | ||
2481 | 17 | return ns |
2482 | end function | |
2483 | ||
2484 | --** | |
2485 | -- Remove all nesting from a sequence. | |
2486 | -- | |
2487 | -- Parameters: | |
2488 | -- # ##s## : the sequence to flatten out. | |
2489 | -- # ##delim## : An optional delimiter to place after each flattened sub-sequence (except | |
2490 | -- the last one). | |
2491 | -- | |
2492 | -- Returns: | |
2493 | -- A **sequence**, of atoms, all the atoms in ##s## enumerated. | |
2494 | -- | |
2495 | -- Comments: | |
2496 | -- * If you consider a sequence as a tree, then the enumeration is performed | |
2497 | -- by left-right reading of the tree. The elements are simply read left to | |
2498 | -- right, without any care for braces. | |
2499 | -- * Empty sub-sequences are stripped out entirely. | |
2500 | -- | |
2501 | -- Example 1: | |
2502 | -- | |
2503 | -- s = flatten({{18, 19}, 45, {18.4, 29.3}}) | |
2504 | -- -- s is {18, 19, 45, 18.4, 29.3} | |
2505 | -- | |
2506 | -- | |
2507 | -- Example 2: | |
2508 | -- | |
2509 | -- s = flatten({18,{ 19, {45}}, {18.4, {}, 29.3}}) | |
2510 | -- -- s is {18, 19, 45, 18.4, 29.3} | |
2511 | -- | |
2512 | -- | |
2513 | -- Example 3: | |
2514 | -- | |
2515 | -- Using the delimiter argument. | |
2516 | -- s = flatten({"abc", "def", "ghi"}, ", ") | |
2517 | -- -- s is "abc, def, ghi" | |
2518 | -- | |
2519 | ||
2520 | ||
2521 | 241 | |
2522 | sequence ret | |
2523 | object x | |
2524 | integer len | |
2525 | integer pos | |
2526 | ||
2527 | 241 | if atom(delim) then |
2528 | 1 | delim = {delim} |
2529 | end if | |
2530 | 241 | ret = s |
2531 | 241 | pos = 1 |
2532 | 241 | len = length(ret) |
2533 | 241 | while pos <= len do |
2534 | 6336 | x = ret[pos] |
2535 | 6336 | if sequence(x) then |
2536 | 221 | if length(delim) = 0 then |
2537 | 24 | ret = ret[1..pos-1] & flatten(x) & ret[pos+1 .. $] |
2538 | else | |
2539 | 197 | sequence temp = ret[1..pos-1] & flatten(x) |
2540 | 197 | if pos != length(ret) then |
2541 | 182 | ret = temp & delim & ret[pos+1 .. $] |
2542 | else | |
2543 | 15 | ret = temp & ret[pos+1 .. $] |
2544 | end if | |
2545 | end if | |
2546 | 221 | len = length(ret) |
2547 | else | |
2548 | 6115 | pos += 1 |
2549 | end if | |
2550 | 6336 | end while |
2551 | ||
2552 | 241 | return ret |
2553 | end function | |
2554 | ||
2555 | ||
2556 | --** | |
2557 | -- Returns a sequence of three sub-sequences. The sub-sequences contain | |
2558 | -- all the elements less than the supplied pivot value, equal to the pivot, | |
2559 | -- and greater than the pivot. | |
2560 | -- | |
2561 | -- Parameters: | |
2562 | -- # ##data_p## : Either an atom or a list. An atom is treated as if it is one-element sequence. | |
2563 | -- # ##pivot_p## : An object. Default is zero. | |
2564 | -- | |
2565 | -- Returns: | |
2566 | -- A **sequence**, { {less than pivot}, {equal to pivot}, {greater than pivot} } | |
2567 | -- | |
2568 | -- Comments: | |
2569 | -- ##pivot()## is used as a split up a sequence relative to a specific value. | |
2570 | -- | |
2571 | -- Example 1: | |
2572 | -- | |
2573 | -- ? pivot( {7, 2, 8.5, 6, 6, -4.8, 6, 6, 3.341, -8, "text"}, 6 ) | |
2574 | -- -- Ans: {{2, -4.8, 3.341, -8}, {6, 6, 6, 6}, {7, 8.5, "text"}} | |
2575 | -- ? pivot( {4, 1, -4, 6, -1, -7, 9, 10} ) | |
2576 | -- -- Ans: {{-4, -1, -7}, {}, {4, 1, 6, 9, 10}} | |
2577 | -- ? pivot( 5 ) | |
2578 | -- -- Ans: {{}, {}, {5}} | |
2579 | -- | |
2580 | -- | |
2581 | -- Example 2: | |
2582 | -- | |
2583 | -- function quiksort(sequence s) | |
2584 | -- if length(s) < 2 then | |
2585 | -- return s | |
2586 | -- end if | |
2587 | -- sequence k | |
2588 | -- | |
2589 | -- k = pivot(s, s[rand(length(s))]) | |
2590 | -- | |
2591 | -- return quiksort(k[1]) & k[2] & quiksort(k[3]) | |
2592 | -- end function | |
2593 | -- sequence t2 = {5,4,7,2,4,9,1,0,4,32,7,54,2,5,8,445,67} | |
2594 | -- ? quiksort(t2) --> {0,1,2,2,4,4,4,5,5,7,7,8,9,32,54,67,445} | |
2595 | -- | |
2596 | ||
2597 | ||
2598 | 7 | |
2599 | sequence result_ | |
2600 | integer pos_ | |
2601 | ||
2602 | 7 | result_ = {{}, {}, {}} |
2603 | ||
2604 | 7 | if atom(data_p) then |
2605 | 3 | data_p = {data_p} |
2606 | end if | |
2607 | ||
2608 | 7 | for i = 1 to length(data_p) do |
2609 | 27 | pos_ = eu:compare(data_p[i], pivot_p) + 2 |
2610 | 27 | result_[pos_] = append(result_[pos_], data_p[i]) |
2611 | 27 | end for |
2612 | ||
2613 | 7 | return result_ |
2614 | end function | |
2615 | ||
2616 | ||
2617 | --** | |
2618 | -- Implements "List Comprehension" or building a list based on the contents of another list. | |
2619 | -- | |
2620 | -- Parameters: | |
2621 | -- # ##source## : A sequence. The list of items to base the new list upon. | |
2622 | -- # ##transformer## : One or more routine_ids. These are [[:routine_id | routine ids]] | |
2623 | -- of functions that must receive three parameters (object x, sequence i, object u) | |
2624 | -- where 'x' is an item in the ##source## list, 'i' contains the position that 'x' is | |
2625 | -- found in the ##source## list and the length of ##source##, and 'u' | |
2626 | -- is the ##user_data## value. Each transformer | |
2627 | -- must return a two-element sequence. If the first element is zero, then build_list() continues | |
2628 | -- on with the next transformer function for the same 'x'. If the first element is not | |
2629 | -- zero, the second element is added to the new list being built (other elements | |
2630 | -- are ignored) and build_list skips the rest of the transformers and processes | |
2631 | -- the next element in ##source##. | |
2632 | -- # ##singleton## : An integer. If zero then the transformer functions return multiple | |
2633 | -- list elements. If not zero then the transformer functions return | |
2634 | -- a single item (which might be a sequence). | |
2635 | -- # ##user_data## : Any object. This is passed unchanged to each transformer function. | |
2636 | -- | |
2637 | -- Returns: | |
2638 | -- A **sequence**, The new list of items. | |
2639 | -- | |
2640 | -- Comments: | |
2641 | -- * If the transformer is -1, then the source item is just copied. | |
2642 | -- | |
2643 | -- Example 1: | |
2644 | -- | |
2645 | -- function remitem(object x, sequence i, object q) | |
2646 | -- if (x < q) then | |
2647 | -- return {0} -- no output | |
2648 | -- else | |
2649 | -- return {1,x} -- copy 'x' | |
2650 | -- end if | |
2651 | -- end function | |
2652 | -- | |
2653 | -- sequence s | |
2654 | -- -- Remove negative elements (x < 0) | |
2655 | -- s = build_list({-3, 0, 1.1, -2, 2, 3, -1.5}, routine_id("remitem"), , 0) | |
2656 | -- -- s is {0, 1.1, 2, 3} | |
2657 | -- | |
2658 | ||
2659 | 6 | |
2660 | 6 | sequence result = {} |
2661 | sequence x | |
2662 | object new_x | |
2663 | ||
2664 | -- Special case where only one transformer is supplied. | |
2665 | 6 | if integer(transformer) then |
2666 | 4 | transformer = {transformer} |
2667 | end if | |
2668 | ||
2669 | 6 | for i = 1 to length(source) do |
2670 | 41 | x = {source[i], {i, length(source)}, user_data} |
2671 | ||
2672 | 41 | for j = 1 to length(transformer) do |
2673 | ||
2674 | 49 | if transformer[j] >= 0 then |
2675 | 40 | new_x = call_func(transformer[j], x) |
2676 | 40 | if length(new_x) = 0 then |
2677 | -- This didn't return anything so go to the next transformer. | |
2678 | 2 | continue |
2679 | end if | |
2680 | 38 | if new_x[1] = 0 then |
2681 | -- This didn't return anything so go to the next transformer. | |
2682 | 14 | continue |
2683 | end if | |
2684 | 24 | if new_x[1] < 0 then |
2685 | -- This didn't return anything and skip other transformers. | |
2686 | 0 | exit |
2687 | end if | |
2688 | ||
2689 | 24 | new_x = new_x[2] |
2690 | else | |
2691 | -- Just copy the input. | |
2692 | 9 | new_x = x[1] |
2693 | end if | |
2694 | ||
2695 | 33 | if singleton then |
2696 | 18 | result = append(result, new_x) |
2697 | else | |
2698 | 15 | result &= new_x |
2699 | end if | |
2700 | ||
2701 | -- Stop calling any more transformers for this input item. | |
2702 | 33 | exit |
2703 | ||
2704 | 0 | end for |
2705 | ||
2706 | ||
2707 | 41 | end for |
2708 | ||
2709 | 6 | return result |
2710 | end function | |
2711 | ||
2712 | --** | |
2713 | -- Transforms the input sequence by using one or more user-supplied transformers. | |
2714 | -- | |
2715 | -- Parameters: | |
2716 | -- # ##source_data## : A sequence to be transformed. | |
2717 | -- # ##transformer_rids## : An object. One or more routine_ids used to transform the input. | |
2718 | -- | |
2719 | -- Returns: | |
2720 | -- The source **sequence**, that has been transformed. | |
2721 | -- | |
2722 | -- Comments: | |
2723 | -- * This works by calling each transformer in order, passing to it the result | |
2724 | -- of the previous transformation. Of course, the first transformer gets the | |
2725 | -- original sequence as passed to this routine. | |
2726 | -- * Each transformer routine takes one or more parameters. The first is a source sequence | |
2727 | -- to be transformed and others are any user data that may have been supplied | |
2728 | -- to the ##transform## routine. | |
2729 | -- * Each transformer routine returns a transformed sequence. | |
2730 | -- * The ##transformer_rids## parameters is either a single routine_id or a sequence | |
2731 | -- of routine_ids. In this second case, the routine_id may actually be a | |
2732 | -- multi-element sequence containing the real routine_id and some user data to | |
2733 | -- pass to the transformer routine. If there is no user data then the transformer | |
2734 | -- is called with only one parameter. | |
2735 | -- | |
2736 | -- Examples: | |
2737 | -- | |
2738 | -- res = transform(" hello ", { | |
2739 | -- {routine_id("trim"), " ",0}, | |
2740 | -- routine_id("upper"), | |
2741 | -- {routine_id("replace_all"), "O", "A"} | |
2742 | -- }) | |
2743 | -- --> "HELLA" | |
2744 | -- | |
2745 | ||
2746 | 2 | |
2747 | sequence lResult | |
2748 | ||
2749 | 2 | lResult = source_data |
2750 | 2 | if atom(transformer_rids) then |
2751 | 1 | transformer_rids = {transformer_rids} |
2752 | end if | |
2753 | ||
2754 | 2 | for i = 1 to length(transformer_rids) do |
2755 | 4 | if atom(transformer_rids[i]) then |
2756 | 2 | lResult = call_func(transformer_rids[i], {lResult}) |
2757 | else | |
2758 | 2 | lResult = call_func(transformer_rids[i][1], {lResult} & transformer_rids[i][2..$]) |
2759 | end if | |
2760 | 4 | end for |
2761 | 2 | return lResult |
2762 | ||
2763 | end function | |
2764 | ||
2765 | --** | |
2766 | -- Calculates the similarity between two sequences. | |
2767 | -- | |
2768 | -- Parameters: | |
2769 | -- # ##A## : A sequence. | |
2770 | -- # ##B## : A sequence. | |
2771 | -- | |
2772 | -- Returns: | |
2773 | -- An **atom**, the closer to zero, the more the two sequences are alike. | |
2774 | -- | |
2775 | -- Comments: | |
2776 | -- The calculation is weighted to give mismatched elements towards the front | |
2777 | -- of the sequences larger scores. This means that sequences that differ near | |
2778 | -- the begining are considered more un-alike than mismatches towards the end of | |
2779 | -- the sequences. Also, unmatched elements from the first sequence are weighted more | |
2780 | -- than unmatched elements from the second sequence. | |
2781 | -- | |
2782 | -- Two identical sequences return zero. A non-zero means that they are not the same | |
2783 | -- and larger values indicate a larger differences. | |
2784 | -- | |
2785 | -- Example 1: | |
2786 | -- | |
2787 | -- ? sim_index("sit", "sin") --> 0.08784 | |
2788 | -- ? sim_index("sit", "sat") --> 0.32394 | |
2789 | -- ? sim_index("sit", "skit") --> 0.34324 | |
2790 | -- ? sim_index("sit", "its") --> 0.68293 | |
2791 | -- ? sim_index("sit", "kit") --> 0.86603 | |
2792 | -- | |
2793 | -- ? sim_index("knitting", "knitting") --> 0.00000 | |
2794 | -- ? sim_index("kitting", "kitten") --> 0.09068 | |
2795 | -- ? sim_index("knitting", "knotting") --> 0.27717 | |
2796 | -- ? sim_index("knitting", "kitten") --> 0.35332 | |
2797 | -- ? sim_index("abacus","zoological") --> 0.76304 | |
2798 | -- | |
2799 | ||
2800 | 4 | |
2801 | atom accum_score | |
2802 | atom pos_factor | |
2803 | integer indx_a | |
2804 | integer indx_b | |
2805 | sequence used_A | |
2806 | sequence used_B | |
2807 | ||
2808 | -- First pass scores only matching runs of elements. | |
2809 | 4 | accum_score = 0 |
2810 | 4 | indx_a = 1 |
2811 | 4 | used_A = repeat(0, length(A)) |
2812 | 4 | used_B = repeat(0, length(B)) |
2813 | 4 | while indx_a <= length(A) label "DoA" do |
2814 | 9 | pos_factor = power((1 + length(A) - indx_a) / length(A),2) |
2815 | 9 | indx_b = 1 |
2816 | 9 | while indx_b <= length(B) do |
2817 | 19 | if equal(A[indx_a],B[indx_b]) then |
2818 | 7 | accum_score += power((indx_b - indx_a) * pos_factor,2) |
2819 | 7 | while indx_a <= length(A) and indx_b <= length(B) with entry do |
2820 | 6 | if not equal(A[indx_a], B[indx_b]) then |
2821 | 3 | exit |
2822 | end if | |
2823 | entry | |
2824 | 10 | used_B[indx_b] = 1 |
2825 | 10 | used_A[indx_a] = 1 |
2826 | 10 | indx_a += 1 |
2827 | 10 | indx_b += 1 |
2828 | 10 | end while |
2829 | 7 | continue "DoA" |
2830 | end if | |
2831 | 12 | indx_b += 1 |
2832 | 12 | end while |
2833 | 2 | indx_a += 1 |
2834 | 2 | end while |
2835 | ||
2836 | -- Now score the unused elements from A. | |
2837 | 4 | for i = 1 to length(A) do |
2838 | 12 | if used_A[i] = 0 then |
2839 | 2 | pos_factor = power((1 + length(A) - i) / length(A),2) |
2840 | 2 | accum_score += power((length(A) - i + 1) * pos_factor,2) |
2841 | end if | |
2842 | 12 | end for |
2843 | ||
2844 | -- Now score the unused elements from B. | |
2845 | 4 | integer total_elems = length(A) |
2846 | 4 | for i = 1 to length(B) do |
2847 | 13 | if used_B[i] = 0 then |
2848 | 3 | pos_factor = power((1 + length(B) - i) / length(B),2) |
2849 | 3 | accum_score += (length(B) - i + 1) * pos_factor |
2850 | 3 | total_elems += 1 |
2851 | end if | |
2852 | 13 | end for |
2853 | ||
2854 | 4 | return power(accum_score / power(total_elems,2), 0.5) |
2855 | end function | |
2856 | ||
2857 | --** | |
2858 | -- Indicates that [[:remove_subseq]]() must not replace removed sub-sequences | |
2859 | -- with an alternative value. | |
2860 | 101 | public constant SEQ_NOALT = {{1.23456}} |
2861 | ||
2862 | ||
2863 | --** | |
2864 | -- Removes all sub-sequences from the supplied sequence, optionally | |
2865 | -- replacing them with a supplied alternative value. One common use | |
2866 | -- is to remove all strings from a mixed set of numbers and strings. | |
2867 | -- | |
2868 | -- Parameters: | |
2869 | -- # ##source_list## : A sequence from which sub-sequences are removed. | |
2870 | -- # ##alt_value## : An object. The default is SEQ_NOALT, which causes sub-sequences | |
2871 | -- to be physically removed, otherwise any other value will be | |
2872 | -- used to replace the sub-sequence. | |
2873 | -- | |
2874 | -- Returns: | |
2875 | -- A **sequence**, which contains only the atoms from ##source_list## and optionally | |
2876 | -- the ##alt_value## where sub-sequences used to be. | |
2877 | -- | |
2878 | -- Example: | |
2879 | -- | |
2880 | -- sequence s = remove_subseq({4,6,"Apple",0.1, {1,2,3}, 4}) | |
2881 | -- -- 's' is now {4, 6, 0.1, 4} -- length now 4 | |
2882 | -- s = remove_subseq({4,6,"Apple",0.1, {1,2,3}, 4}, -1) | |
2883 | -- -- 's' is now {4, 6, -1, 0.1, -1, 4} -- length unchanged. | |
2884 | -- | |
2885 | -- | |
2886 | ||
2887 | 22 | |
2888 | sequence lResult | |
2889 | 22 | integer lCOW = 0 |
2890 | ||
2891 | 22 | for i = 1 to length(source_list) do |
2892 | 90 | if atom(source_list[i]) then |
2893 | 70 | if lCOW != 0 then |
2894 | 10 | if lCOW != i then |
2895 | 8 | lResult[lCOW] = source_list[i] |
2896 | end if | |
2897 | 10 | lCOW += 1 |
2898 | end if | |
2899 | 70 | continue |
2900 | end if | |
2901 | ||
2902 | 20 | if lCOW = 0 then |
2903 | 16 | lResult = source_list |
2904 | 16 | lCOW = i |
2905 | end if | |
2906 | 20 | if not equal(alt_value, SEQ_NOALT) then |
2907 | 5 | lResult[lCOW] = alt_value |
2908 | 5 | lCOW += 1 |
2909 | end if | |
2910 | ||
2911 | 20 | end for |
2912 | ||
2913 | 22 | if lCOW = 0 then |
2914 | 6 | return source_list |
2915 | end if | |
2916 | 16 | return lResult[1.. lCOW - 1] |
2917 | end function | |
2918 | ||
2919 | --** | |
2920 | -- These are used with the [[:remove_dups]]() function. | |
2921 | -- ** RD_INPLACE removes items while preserving the original order of the unique items. | |
2922 | -- ** RD_PRESORTED assumes that the elements in ##source_data## are already sorted. If they | |
2923 | -- are not already sorted, this option merely removed adjacent duplicate elements. | |
2924 | -- ** RD_SORT will return the unique elements in ascending sorted order. | |
2925 | ||
2926 | public enum | |
2927 | 101 | RD_INPLACE, |
2928 | 101 | RD_PRESORTED, |
2929 | 101 | RD_SORT |
2930 | ||
2931 | --** | |
2932 | -- Removes duplicate elements | |
2933 | -- | |
2934 | -- Parameters: | |
2935 | -- # ##source_data## : A sequence that may contain duplicated elements | |
2936 | -- # ##proc_option## : One of RD_INPLACE, RD_PRESORTED, or RD_SORT. | |
2937 | -- ** RD_INPLACE removes items while preserving the original order of the unique items. | |
2938 | -- ** RD_PRESORTED assumes that the elements in ##source_data## are already sorted. If they | |
2939 | -- are not already sorted, this option merely removed adjacent duplicate elements. | |
2940 | -- ** RD_SORT will return the unique elements in ascending sorted order. | |
2941 | -- | |
2942 | -- Returns: | |
2943 | -- A **sequence**, that contains only the unique elements from ##source_data##. | |
2944 | -- | |
2945 | -- Example 1: | |
2946 | -- | |
2947 | -- sequence s = { 4,7,9,7,2,5,5,9,0,4,4,5,6,5} | |
2948 | -- ? remove_dups(s, RD_INPLACE) --> {4,7,9,2,5,0,6} | |
2949 | -- ? remove_dups(s, RD_SORT) --> {0,2,4,5,6,7,9} | |
2950 | -- ? remove_dups(s, RD_PRESORTED) --> {4,7,9,7,2,5,9,0,4,5,6,5} | |
2951 | -- ? remove_dups(sort(s), RD_PRESORTED) --> {0,2,4,5,6,7,9} | |
2952 | -- | |
2953 | -- | |
2954 | 17 | |
2955 | integer lTo | |
2956 | integer lFrom | |
2957 | ||
2958 | 17 | if length(source_data) < 2 then |
2959 | 3 | return source_data |
2960 | end if | |
2961 | ||
2962 | 14 | if proc_option = RD_SORT then |
2963 | 11 | source_data = sort(source_data) |
2964 | 11 | proc_option = RD_PRESORTED |
2965 | end if | |
2966 | 14 | if proc_option = RD_PRESORTED then |
2967 | 13 | lTo = 1 |
2968 | 13 | lFrom = 2 |
2969 | ||
2970 | 13 | while lFrom <= length(source_data) do |
2971 | 108 | if not equal(source_data[lFrom], source_data[lTo]) then |
2972 | 49 | lTo += 1 |
2973 | 49 | if lTo != lFrom then |
2974 | 34 | source_data[lTo] = source_data[lFrom] |
2975 | end if | |
2976 | end if | |
2977 | 108 | lFrom += 1 |
2978 | 108 | end while |
2979 | 13 | return source_data[1 .. lTo] |
2980 | end if | |
2981 | ||
2982 | 1 | sequence lResult |
2983 | 1 | lResult = {} |
2984 | 1 | for i = 1 to length(source_data) do |
2985 | 14 | if not find(source_data[i], lResult) then |
2986 | 7 | lResult = append(lResult, source_data[i]) |
2987 | end if | |
2988 | 14 | end for |
2989 | 1 | return lResult |
2990 | ||
2991 | end function | |
2992 | ||
2993 | public enum | |
2994 | 101 | COMBINE_UNSORTED = 0, |
2995 | 101 | COMBINE_SORTED, |
2996 | $ | |
2997 | ||
2998 | --** | |
2999 | -- Combines all the sub-sequences into a single, optionally sorted, list | |
3000 | -- | |
3001 | -- Parameters: | |
3002 | -- # ##source_data## : A sequence that contains sub-sequences to be combined. | |
3003 | -- # ##proc_option## : An integer; COMBINE_UNSORTED to return a non-sorted list and | |
3004 | -- COMBINE_SORTED (the default) to return a sorted list. | |
3005 | -- | |
3006 | -- Returns: | |
3007 | -- A **sequence**, that contains all the elements from all the first-level of | |
3008 | -- sub-sequences from ##source_data##. | |
3009 | -- | |
3010 | -- Comments: | |
3011 | -- The elements in the sub-sequences do not have to be pre-sorted. | |
3012 | -- | |
3013 | -- Only one level of sub-sequence is combined. | |
3014 | -- | |
3015 | -- Example 1: | |
3016 | -- | |
3017 | -- sequence s = { {4,7,9}, {7,2,5,9}, {0,4}, {5}, {6,5}} | |
3018 | -- ? combine(s, COMBINE_SORTED) --> {0,2,4,4,5,5,5,6,7,7,9,9} | |
3019 | -- ? combine(s, COMBINE_UNSORTED) --> {4,7,9,7,2,5,9,0,4,5,6,5} | |
3020 | -- | |
3021 | -- | |
3022 | -- Example 2: | |
3023 | -- | |
3024 | -- sequence s = { {"cat", "dog"}, {"fish", "whale"}, {"wolf"}, {"snail", "worm"}} | |
3025 | -- ? combine(s) --> {"cat","dog","fish","snail","whale","wolf","worm"} | |
3026 | -- ? combine(s, COMBINE_UNSORTED) --> {"cat","dog","fish","whale","wolf","snail","worm"} | |
3027 | -- | |
3028 | -- | |
3029 | -- Example 3: | |
3030 | -- | |
3031 | -- sequence s = { "cat", "dog","fish", "whale", "wolf", "snail", "worm"} | |
3032 | -- ? combine(s) --> "aaacdeffghhiilllmnooorsstwww" | |
3033 | -- ? combine(s, COMBINE_UNSORTED) --> "catdogfishwhalewolfsnailworm" | |
3034 | -- | |
3035 | -- | |
3036 | 8 | |
3037 | sequence lResult | |
3038 | 8 | integer lTotalSize = 0 |
3039 | integer lPos | |
3040 | ||
3041 | 8 | if length(source_data) = 0 then |
3042 | 1 | return {} |
3043 | end if | |
3044 | ||
3045 | 7 | if length(source_data) = 1 then |
3046 | 1 | return source_data[1] |
3047 | end if | |
3048 | ||
3049 | 6 | for i = 1 to length(source_data) do |
3050 | 32 | lTotalSize += length(source_data[i]) |
3051 | 32 | end for |
3052 | ||
3053 | 6 | lResult = repeat(0, lTotalSize) |
3054 | 6 | lPos = 1 |
3055 | 6 | for i = 1 to length(source_data) do |
3056 | 32 | lResult[lPos .. length(source_data[i]) + lPos - 1] = source_data[i] |
3057 | 32 | lPos += length(source_data[i]) |
3058 | 32 | end for |
3059 | ||
3060 | 6 | if proc_option = COMBINE_SORTED then |
3061 | 3 | return sort(lResult) |
3062 | else | |
3063 | 3 | return lResult |
3064 | end if | |
3065 | end function | |
3066 | ||
3067 | --/desc Pads /i source_data to the right until its length reaches /i min_size using /i new_data as filler. | |
3068 | --/ret The padded sequence, unchanged if its size was not less than /i min_size on input. | |
3069 | --** | |
3070 | -- Ensures that the supplied sequence is at least the supplied minimum length. | |
3071 | -- | |
3072 | -- Parameters: | |
3073 | -- # ##source_data## : A sequence that might need extending. | |
3074 | -- # ##min_size##: An integer. The minimum length that ##source_data## must be. | |
3075 | -- # ##new_data##: An object. This used to when ##source_data## needs to be extended, | |
3076 | -- in which case it is appended as many times as required to make the length | |
3077 | -- equal to ##min_size##. | |
3078 | -- | |
3079 | -- Returns: | |
3080 | -- A **sequence**. | |
3081 | -- | |
3082 | -- Example: | |
3083 | -- | |
3084 | -- sequence s | |
3085 | -- s = minsize({4,3,6,2,7,1,2}, 10, -1) --> {4,3,6,2,7,1,2,-1,-1,-1} | |
3086 | -- s = minsize({4,3,6,2,7,1,2}, 5, -1) --> {4,3,6,2,7,1,2} | |
3087 | -- | |
3088 | -- | |
3089 | 2 | |
3090 | ||
3091 | 2 | if length(source_data) < min_size then |
3092 | 1 | source_data &= repeat(new_data, min_size - length(source_data)) |
3093 | end if | |
3094 | ||
3095 | 2 | return source_data |
3096 | end function | |
3097 |