Skip to content

Commit a710f3d

Browse files
✨ feat(Seq): Add insert, remove, slice, and splice methods.
1 parent 97861ef commit a710f3d

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed

src/seq.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,52 @@ Seq.prototype.get = function ( index ) {
7676

7777
} ;
7878

79+
Seq.prototype.insert = function ( index , value ) {
80+
81+
if ( index < 0 || index >= this.len( ) ) throw new Error( `wrong index '${index}'` ) ;
82+
83+
const [prefix, rest] = this.tree.split( ( m ) => m > index ) ;
84+
return new Seq(prefix.push(value).concat(rest)) ;
85+
86+
} ;
87+
88+
Seq.prototype.remove = function ( index ) {
89+
90+
if ( index < 0 || index >= this.len( ) ) throw new Error( `wrong index '${index}'` ) ;
91+
92+
const { left , right } = this.tree.splitTree( ( m ) => m > index , size.zero( ) ) ;
93+
return new Seq(left.concat(right)) ;
94+
95+
} ;
96+
97+
Seq.prototype.slice = function ( start = 0 , end = this.len( ) ) {
98+
99+
if ( start < -this.len( ) || start > this.len( ) ) throw new Error( `wrong start '${start}'` ) ;
100+
if ( end < -this.len( ) || end > this.len( ) ) throw new Error( `wrong end '${end}'` ) ;
101+
102+
if ( start < 0 ) start += this.len( ) ;
103+
if ( end < 0 ) end += this.len( ) ;
104+
105+
const [ prefix , rest ] = this.tree.split( ( m ) => m > start ) ;
106+
const [ slice , suffix ] = rest.split( ( m ) => m > end - start ) ;
107+
return new Seq(slice);
108+
109+
} ;
110+
111+
Seq.prototype.splice = function ( start , deleteCount , ...items ) {
112+
113+
const length = this.len( ) ;
114+
115+
if ( start < -length || start >= length ) throw new Error( `wrong start '${start}'` ) ;
116+
117+
if ( start < 0 ) start += length ;
118+
119+
const [ prefix , rest ] = this.tree.split( ( m ) => m > start ) ;
120+
const [ deleted , suffix ] = rest.split( ( m ) => m > deleteCount ) ;
121+
return [ new Seq(prefix.append(items).concat(suffix)) , new Seq(deleted) ] ;
122+
123+
} ;
124+
79125

80126
Seq.prototype[Symbol.iterator] = function ( ) {
81127
return this.tree[Symbol.iterator]( ) ;

test/src/seq.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,172 @@ test('@aureooms/js-fingertree github issue #73', t => {
7575
t.deepEqual(list(s), list('ab'+c+'de'));
7676
}
7777
}) ;
78+
79+
test('Seq#slice', t => {
80+
81+
const s = Seq.from('abcde');
82+
t.deepEqual(list('abcde'), list(s.slice(0,5)));
83+
t.deepEqual(list('abcd'), list(s.slice(0,4)));
84+
t.deepEqual(list('bcde'), list(s.slice(1,5)));
85+
t.deepEqual(list('bcd'), list(s.slice(1,4)));
86+
t.deepEqual(list('cde'), list(s.slice(2,5)));
87+
88+
}) ;
89+
90+
// Examples from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
91+
test('Seq#slice (MDN Return a portion of an existing array)', t => {
92+
const fruits = Seq.from(['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']);
93+
const citrus = fruits.slice(1, 3);
94+
95+
t.deepEqual(['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'], list(fruits));
96+
t.deepEqual(['Orange', 'Lemon'], list(citrus));
97+
});
98+
99+
test('Seq#slice (MDN Using slice)', t => {
100+
101+
const myHonda = { color: 'red', wheels: 4, engine: { cylinders: 4, size: 2.2 } }
102+
const myCar = Seq.from([myHonda, 2, 'cherry condition', 'purchased 1997']);
103+
const newCar = myCar.slice(0, 2)
104+
105+
t.deepEqual([myHonda, 2, 'cherry condition', 'purchased 1997'], list(myCar));
106+
t.deepEqual([myHonda, 2], list(newCar));
107+
108+
t.is('red', myCar.get(0).color);
109+
t.is('red', newCar.get(0).color);
110+
111+
myCar.get(0).color = 'purple';
112+
t.is('purple', myCar.get(0).color);
113+
t.is('purple', newCar.get(0).color);
114+
115+
newCar.get(0).color = 'green';
116+
t.is('green', myCar.get(0).color);
117+
t.is('green', newCar.get(0).color);
118+
119+
});
120+
121+
test('Seq#remove', t => {
122+
123+
const string = 'abcde' ;
124+
const s = Seq.from(string);
125+
for (const i of range(0, string.length)) {
126+
const result = s.remove(i);
127+
t.deepEqual(list(string.slice(0,i)+string.slice(i+1)), list(result));
128+
}
129+
130+
}) ;
131+
132+
test('Seq#insert', t => {
133+
134+
const string = 'abcde' ;
135+
const s = Seq.from(string);
136+
137+
for (const i of range(0, string.length)) {
138+
const result = s.insert(i, string[i].toUpperCase());
139+
t.deepEqual(list(string.slice(0,i)+string[i].toUpperCase()+string.slice(i)), list(result));
140+
}
141+
142+
}) ;
143+
144+
test('Seq#splice', t => {
145+
146+
const string = 'abcde' ;
147+
const s = Seq.from(string);
148+
for (const i of range(-string.length, string.length)) {
149+
const [result, removed] = s.splice(i,1);
150+
const _i = i < 0 ? i + string.length : i;
151+
t.deepEqual(list(string.slice(0,_i)+string.slice(_i+1)), list(result));
152+
t.deepEqual(list(string[_i]), list(removed));
153+
}
154+
155+
for (const i of range(0, string.length)) {
156+
const [result, removed] = s.splice(i,1, ...string.slice(0,i+1).toUpperCase());
157+
t.deepEqual(list(string.slice(0,i)+string.slice(0,i+1).toUpperCase()+string.slice(i+1)), list(result));
158+
t.deepEqual(list(string[i]), list(removed));
159+
}
160+
161+
for (const i of range(0, string.length)) {
162+
const [result, removed] = s.splice(i,0, ...string.slice(0,i+1).toUpperCase());
163+
t.deepEqual(list(string.slice(0,i)+string.slice(0,i+1).toUpperCase()+string.slice(i)), list(result));
164+
t.deepEqual([], list(removed));
165+
}
166+
167+
for (const i of range(0, string.length)) {
168+
const [result, removed] = s.splice(i,undefined, ...string.slice(0,i+1).toUpperCase());
169+
t.deepEqual(list(string.slice(0,i)+string.slice(0,i+1).toUpperCase()), list(result));
170+
t.deepEqual(list(string.slice(i)), list(removed));
171+
}
172+
173+
}) ;
174+
175+
// Examples from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
176+
test('Seq#splice (MDN Remove 0 (zero) elements before index 2, and insert "drum")', t => {
177+
const myFish = Seq.from(['angel', 'clown', 'mandarin', 'sturgeon']);
178+
const [result, removed] = myFish.splice(2, 0, 'drum');
179+
180+
t.deepEqual(['angel', 'clown', 'mandarin', 'sturgeon'], list(myFish));
181+
t.deepEqual(["angel", "clown", "drum", "mandarin", "sturgeon"], list(result));
182+
t.deepEqual([], list(removed));
183+
}) ;
184+
185+
test('Seq#splice (MDN Remove 0 (zero) elements before index 2, and insert "drum" and "guitar")', t => {
186+
const myFish = Seq.from(['angel', 'clown', 'mandarin', 'sturgeon']);
187+
const [result, removed] = myFish.splice(2, 0, 'drum', 'guitar');
188+
189+
t.deepEqual(['angel', 'clown', 'mandarin', 'sturgeon'], list(myFish));
190+
t.deepEqual(["angel", "clown", "drum", "guitar", "mandarin", "sturgeon"], list(result));
191+
t.deepEqual([], list(removed));
192+
}) ;
193+
194+
test('Seq#splice (MDN Remove 1 element at index 3)', t => {
195+
const myFish = Seq.from(['angel', 'clown', 'drum', 'mandarin', 'sturgeon']);
196+
const [result, removed] = myFish.splice(3, 1);
197+
198+
t.deepEqual(['angel', 'clown', 'drum', 'mandarin', 'sturgeon'], list(myFish));
199+
t.deepEqual(["angel", "clown", "drum", "sturgeon"], list(result));
200+
t.deepEqual(["mandarin"], list(removed));
201+
}) ;
202+
203+
test('Seq#splice (MDN Remove 1 element at index 2, and insert "trumpet")', t => {
204+
const myFish = Seq.from(['angel', 'clown', 'drum', 'sturgeon']);
205+
const [result, removed] = myFish.splice(2, 1, 'trumpet');
206+
207+
t.deepEqual(['angel', 'clown', 'drum', 'sturgeon'], list(myFish));
208+
t.deepEqual(["angel", "clown", "trumpet", "sturgeon"], list(result));
209+
t.deepEqual(["drum"], list(removed));
210+
}) ;
211+
212+
test('Seq#splice (MDN Remove 2 elements from index 0, and insert "parrot", "anemone" and "blue")', t => {
213+
const myFish = Seq.from(['angel', 'clown', 'trumpet', 'sturgeon']);
214+
const [result, removed] = myFish.splice(0, 2, 'parrot', 'anemone', 'blue');
215+
216+
t.deepEqual(['angel', 'clown', 'trumpet', 'sturgeon'], list(myFish));
217+
t.deepEqual(["parrot", "anemone", "blue", "trumpet", "sturgeon"], list(result));
218+
t.deepEqual(["angel", "clown"], list(removed));
219+
}) ;
220+
221+
test('Seq#splice (MDN Remove 2 elements from index 2)', t => {
222+
const myFish = Seq.from(['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon']);
223+
const [result, removed] = myFish.splice(2, 2);
224+
225+
t.deepEqual(['parrot', 'anemone', 'blue', 'trumpet', 'sturgeon'], list(myFish));
226+
t.deepEqual(["parrot", "anemone", "sturgeon"], list(result));
227+
t.deepEqual(["blue", "trumpet"], list(removed));
228+
}) ;
229+
230+
test('Seq#splice (MDN Remove 1 element from index -2)', t => {
231+
const myFish = Seq.from(['angel', 'clown', 'mandarin', 'sturgeon']);
232+
const [result, removed] = myFish.splice(-2, 1);
233+
234+
t.deepEqual(['angel', 'clown', 'mandarin', 'sturgeon'], list(myFish));
235+
t.deepEqual(["angel", "clown", "sturgeon"], list(result));
236+
t.deepEqual(["mandarin"], list(removed));
237+
}) ;
238+
239+
test('Seq#splice (MDN Remove all elements after index 2 (incl.))', t => {
240+
const myFish = Seq.from(['angel', 'clown', 'mandarin', 'sturgeon']);
241+
const [result, removed] = myFish.splice(2);
242+
243+
t.deepEqual(['angel', 'clown', 'mandarin', 'sturgeon'], list(myFish));
244+
t.deepEqual(["angel", "clown"], list(result));
245+
t.deepEqual(["mandarin", "sturgeon"], list(removed));
246+
}) ;

0 commit comments

Comments
 (0)