1 Order : SequenceableCollection {
3 var <>array, <>indices;
9 *newFromIndices { arg array, indices;
10 ^super.newCopyArgs(array, indices)
14 array = Array.new(size);
15 indices = Array.new(size);
18 makeEmpty { this.clear }
21 ^this.class.newCopyArgs(array.copy, indices.copy)
24 asArray { ^array.copy }
27 indices.do { |index, i|
28 function.value(array.at(i), index, i)
32 doRange { arg function, from = 0, to;
33 if(from <= indices.last) {
34 if(to.isNil) { to = indices.size - 1 } { to = min(to, this.lastIndex) };
35 for(this.slotFor(from), to) { |i|
36 function.value(array.at(i), indices.at(i), i)
41 keysValuesDo { arg function;
42 indices.do { |index, i|
43 function.value(index, array.at(i), i)
47 size { ^indices.size }
49 lastIndex { ^indices.last }
51 // current write position
53 var index = this.lastIndex;
54 ^if(index.isNil) { 0 } { index + 1 }
58 array = array.add(obj);
59 indices = indices.add(this.pos);
63 this.prPutSlot(this.nextSlotFor(index), index, obj)
67 var slot = this.slotFor(index);
69 if(indices.at(slot) == index) {
75 removeAt { arg index, obj;
76 var nextSlot = this.nextSlotFor(index), slot;
77 ^if(nextSlot.notNil) {
78 slot = max(0, nextSlot - 1);
79 if(indices.at(slot) == index) { this.removeAtSlot(slot) }
83 removeAtSlot { arg slot;
84 indices.removeAt(slot);
93 collect { arg function;
94 ^this.copy.array_(array.collect(function));
97 select { arg function;
98 var res = this.class.new;
99 this.indicesDo { |item, i|
100 if(function.value(item, i)) { res.put(i, item) }
105 reject { arg function;
106 var res = this.class.new;
107 this.indicesDo { |item, i|
108 if(function.value(item, i).not) { res.put(i, item) }
113 removeAllSuchThat { arg function;
114 var removedItems = this.class.new;
115 var copy = this.copy;
116 copy.indicesDo { | item, i |
117 if ( function.value(item, i) )
120 removedItems = removedItems.put(i, item);
126 selectInPlace { arg function;
127 indices.copy.do { |index, i|
128 if(function.value(array.at(i), index).not) {
134 rejectInPlace { arg function;
135 indices.copy.do { |index, i|
136 if(function.value(array.at(i), index)) {
142 indicesDo { arg function;
143 indices.do { |slot, i|
144 function.value(array.at(i), slot, i)
148 // private implementation
150 resetIndices { arg step = 1, offset = 0;
151 indices = (offset, step .. indices.size - 1);
154 nextSlotFor { arg index;
155 ^indices.indexOfGreaterThan(index) ?? { indices.size }
159 ^max(0, this.nextSlotFor(index) - 1)
162 prPutSlot { arg nextSlot, index, obj;
163 var slot = max(0, nextSlot - 1);
164 if(indices.at(slot) == index) {
167 array = array.insert(nextSlot, obj);
168 indices = indices.insert(nextSlot, index);
178 SparseArray : Order {
180 var <>default, <>defaultSize;
182 *newClear { arg size, default;
183 ^super.new(size).defaultSize_(size).default_(default)
186 *reduceArray { arg array, default;
187 var res = this.new.default_(default);
188 array.do { |item, i| res.putIfNotDefault(i, item) };
189 res.defaultSize = if(default.isNil) { res.size } { array.size };
194 size = size.min(67108864 / 2); // For very large data we must assume sparse indices or we can't initialise the indices here
195 array = Array.new(size);
196 indices = Array.new(size);
199 putIfNotDefault { arg i, item;
200 if(item != default) { this.put(i, item) }
204 ^this.class.newCopyArgs(array.copy, indices.copy, default, defaultSize)
207 asArray { ^this[_] ! this.size }
210 ^super.at(index) ? default
214 if(this.isEmpty) { ^this };
216 function.value(this.at(i), i)
221 var last = super.lastIndex ? (-1);
222 ^if(defaultSize.isNil) {
225 max(last + 1, defaultSize)
230 var last = super.lastIndex ? 0;
231 ^if(defaultSize.isNil) {
234 max(last, defaultSize)
238 // current write position
240 var index = super.lastIndex;
241 ^if(index.isNil) { 0 } { index + 1 }
244 collect { arg function;
245 ^this.class.reduceArray(
246 this.asArray.collect(function),
247 default !? { function.value(default, 0) } )
250 select { arg function;
251 ^this.class.reduceArray(
252 this.asArray.select(function),
253 if(default.notNil and: { function.value(default, 0) }) { default }
257 reject { arg function;
258 ^this.class.reduceArray(
259 this.asArray.reject(function),
260 if(default.notNil and: { function.value(default, 0).not }) { default }
266 ^if (function.isNil or: {function.numArgs < 2}) { // optimized version if no function, or if index is irrelevant
269 this.do {|elem, i| sum = sum + function.value(elem, i); };
273 // if index is irrelevant, assume that the result for all implicit elements is the same
274 sparseSum { | function |
276 "sparseSum : inner array size is %".format(array.size).postln;
277 if (function.isNil) { // optimized version if no function
278 array.do { | elem | sum = sum + elem; };
279 sum = sum + (default * (this.size-array.size));
281 array.do {|elem| sum = sum + function.value(elem); };
282 sum = sum + (function.value(default) * (this.size-array.size));
289 // does not pass the index to each default item: faster than collect
290 sparseCollect { arg function;
291 var res = super.collect(function);
292 default !? { res.default = function.value(default) };
296 sparseSelect { arg function;
297 var res = super.select(function);
298 if(default.notNil and: { function.value(default, 0) }) { res.default = default }
302 sparseReject { arg function;
303 var res = super.reject(function);
304 if(default.notNil and: { function.value(default, 0).not })
305 { res.default = default }
309 sparseRemoveAt { arg index;
310 ^super.removeAt(index)
313 sparseRemove { arg item;
314 var index = super.indexOf(item);
315 ^if(index.notNil) { super.removeAt(index) } { nil }
318 removeAt { arg index;
319 //^this.notYetImplemented(thisMethod)
320 var res, slot = this.slotFor(index), size = indices.size;
321 if(index >= this.size) { ^nil };
323 if(indices[slot] == index) {
324 res = this.removeAtSlot(slot);
327 if(size > 0) { res = default };
328 if(indices.first > index) { slot = -1 };
330 indices = indices[..slot] ++ (indices[slot+1..] - 1);
332 if(defaultSize.notNil and: { defaultSize > 0 } and: { index < defaultSize }) {
333 defaultSize = defaultSize - 1;
339 firstGap { arg from = 0, to;
340 if(indices.first == 0) { ^nil };
341 to = to ?? { indices.size };
343 if(indices[i] != i) { ^i };
349 var slot = array.indexOf(item), res;
350 if(item == default) {
351 res = this.firstGap(0, slot);
352 if(res.notNil) { ^res };
354 ^if(slot.isNil) { nil } { indices[slot] }
358 var ind, list, size = defaultSize ?? { this.size };
360 if(item != default) {
361 list = list.add(item);
362 ind = ind.add(indices.at(i))
365 ^this.class.newFromIndices(list, ind).default_(default).defaultSize_(size)
369 ^if(defaultSize.notNil and: { defaultSize > indices.last }) {
370 defaultSize = defaultSize - 1;
379 var res = this.copy.sparseAddAll(coll);
380 if(defaultSize.notNil) { res.defaultSize_(this.size + coll.size) };
384 sparseAddAll { arg coll;
385 var slot = this.size;
387 if(item != default) { this.put(slot + i, item) }
391 putSeries { arg first, second, last, value;
392 (first, second..last).do { |index|
393 this.put(index, value)
396 atSeries { arg first, second, last;
397 ^(first, second..last).collect { |index|
403 ^if(function.isNil or: {function.numArgs < 2}){
404 if(array.size == this.size){ // full up! default not used (weird)
405 array.minItem(function)
407 array.minItem(function).min(if(function.isNil, default, function.value(default)))
410 super.minItem(function);
414 ^if(function.isNil or: {function.numArgs < 2}){
415 if(array.size == this.size){ // full up! default not used (weird)
416 array.maxItem(function)
418 array.maxItem(function).max(if(function.isNil, default, function.value(default)))
421 super.maxItem(function);
425 // private implementation
427 prPutSlot { arg nextSlot, index, obj;
428 var slot = max(0, nextSlot - 1);
429 index = index.asInteger; // SparseArray supports only integer indices
430 if(indices.at(slot) == index) {
433 array = array.insert(nextSlot, obj);
434 indices = indices.insert(nextSlot, index);