Skip to content

Commit 12e59f2

Browse files
committed
feat: add slice/seq2slice
1 parent 9d16b25 commit 12e59f2

File tree

16 files changed

+3229
-0
lines changed

16 files changed

+3229
-0
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2023 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# seq2slice
22+
23+
> Convert a subsequence string to a [`Slice`][@stdlib/slice/ctor] object.
24+
25+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
26+
27+
<section class="intro">
28+
29+
</section>
30+
31+
<!-- /.intro -->
32+
33+
<!-- Package usage documentation. -->
34+
35+
<section class="usage">
36+
37+
## Usage
38+
39+
```javascript
40+
var seq2slice = require( '@stdlib/slice/seq2slice' );
41+
```
42+
43+
<a name="main"></a>
44+
45+
#### seq2slice( str, len )
46+
47+
Converts a subsequence string to a [`Slice`][@stdlib/slice/ctor] object, where `len` specifies the maximum number of elements allowed in the slice.
48+
49+
```javascript
50+
var s = seq2slice( ':5', 10 );
51+
// returns <Slice>
52+
53+
var v = s.start;
54+
// returns 0
55+
56+
v = s.stop;
57+
// returns 5
58+
59+
v = s.step;
60+
// returns 1
61+
```
62+
63+
A subsequence string has the following format:
64+
65+
```text
66+
<start>:<stop>:<increment>
67+
```
68+
69+
where
70+
71+
- If an `increment` is not specified, the default increment is `1`. An increment of zero is **not** allowed.
72+
- The `start` index is **inclusive**.
73+
- The `stop` index is **exclusive**.
74+
- Both `start` and `stop` indices are _optional_. If not provided, `start` and `stop` default to index extremes. Which extremes correspond to which index depends on whether the `increment` is positive or negative.
75+
- Both `start` and `stop` can be negative; in which case, the corresponding index is resolved by subtracting the respective value from the provided length `len`.
76+
- Both `start` and `stop` can use the `end` keyword (e.g., `end-2::2`, `end-3:`, etc), which supports basic subtraction and division.
77+
- The `end` keyword resolves to the provided length `len`. Thus, `:-1` is equivalent to `:end-1`, `:-2` is equivalent to `:end-2`, and so on and so forth. The exception is when performing a division operation when the `increment` is less than zero; in which case, `end` is equal to `len-1` in order to preserve user expectations when `end/d` equals a whole number and slicing from right-to-left. The result from a division operation is **rounded down** to the nearest integer value.
78+
79+
```javascript
80+
var s = seq2slice( 'end:2:-1', 10 );
81+
// returns <Slice>
82+
83+
var v = s.start;
84+
// returns 9
85+
86+
v = s.stop;
87+
// returns 2
88+
89+
v = s.step;
90+
// returns -1
91+
92+
s = seq2slice( 'end-2:2:-1', 10 );
93+
// returns <Slice>
94+
95+
v = s.start;
96+
// returns 8
97+
98+
v = s.stop;
99+
// returns 2
100+
101+
v = s.step;
102+
// returns -1
103+
104+
s = seq2slice( 'end/2:2:-1', 10 );
105+
// returns <Slice>
106+
107+
v = s.start;
108+
// returns 4
109+
110+
v = s.stop;
111+
// returns 2
112+
113+
v = s.step;
114+
// returns -1
115+
```
116+
117+
</section>
118+
119+
<!-- /.usage -->
120+
121+
<!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
122+
123+
<section class="notes">
124+
125+
## Notes
126+
127+
- When `len` is zero, the function always returns a Slice object equivalent to `0:0:<increment>`.
128+
- The resolved slice start is clamped to the slice index bounds (i.e., `[0, len)`).
129+
- The resolved slice end is upper bound clamped to `len` (i.e., one greater than the last possible index).
130+
- When the increment is negative, the resolved slice end value may be `null`, thus indicating that a non-empty slice should include the first index.
131+
- The function ensures that results satisfy the convention that `:n` combined with `n:` is equivalent to `:` (i.e., selecting all elements). This convention matches Python slice semantics, but diverges from the MATLAB convention where `:n` and `n:` overlap by one element.
132+
- Unlike MATLAB, but like Python, the subsequence string is upper-bound exclusive. For example, in Python, `0:2` corresponds to the sequence `{0,1}`. In MATLAB, `1:3` corresponds to `{1,2,3}`.
133+
134+
</section>
135+
136+
<!-- /.notes -->
137+
138+
<!-- Package usage examples. -->
139+
140+
<section class="examples">
141+
142+
## Examples
143+
144+
<!-- eslint no-undef: "error" -->
145+
146+
```javascript
147+
var seq2slice = require( '@stdlib/slice/seq2slice' );
148+
149+
var s = seq2slice( ':', 5 );
150+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
151+
// => 'start: 0. stop: 5. step: 1.'
152+
153+
s = seq2slice( '2:', 5 );
154+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
155+
// => 'start: 2. stop: 5. step: 1.'
156+
157+
s = seq2slice( ':3', 5 );
158+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
159+
// => 'start: 0. stop: 3. step: 1.'
160+
161+
s = seq2slice( '2:4', 5 );
162+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
163+
// => 'start: 2. stop: 4. step: 1.'
164+
165+
s = seq2slice( '1:4:2', 5 );
166+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
167+
// => 'start: 1. stop: 4. step: 2.'
168+
169+
s = seq2slice( '2::2', 5 );
170+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
171+
// => 'start: 2. stop: 5. step: 2.'
172+
173+
s = seq2slice( ':-2', 5 );
174+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
175+
// => 'start: 0. stop: 3. step: 1.'
176+
177+
s = seq2slice( ':-1:2', 5 );
178+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
179+
// => 'start: 0. stop: 4. step: 2.'
180+
181+
s = seq2slice( '-4:-1:2', 5 );
182+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
183+
// => 'start: 1. stop: 4. step: 2.'
184+
185+
s = seq2slice( '-5:-1', 5 );
186+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
187+
// => 'start: 0. stop: 4. step: 1.'
188+
189+
s = seq2slice( '::-1', 5 );
190+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
191+
// => 'start: 4. stop: null. step: -1.'
192+
193+
s = seq2slice( ':0:-1', 5 );
194+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
195+
// => 'start: 4. stop: 0. step: -1.'
196+
197+
s = seq2slice( '3:0:-1', 5 );
198+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
199+
// => 'start: 3. stop: 0. step: -1.'
200+
201+
s = seq2slice( '-1:-4:-2', 5 );
202+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
203+
// => 'start: 4. stop: 1. step: -2.'
204+
205+
s = seq2slice( ':end', 5 );
206+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
207+
// => 'start: 0. stop: 5. step: 1.'
208+
209+
s = seq2slice( ':end-1', 5 );
210+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
211+
// => 'start: 0. stop: 4. step: 1.'
212+
213+
s = seq2slice( ':end/2', 5 );
214+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
215+
// => 'start: 0. stop: 2. step: 1.'
216+
217+
s = seq2slice( 'end/2::-1', 5 );
218+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
219+
// => 'start: 2. stop: null. step: -1.'
220+
221+
s = seq2slice( 'end-2::-1', 5 );
222+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
223+
// => 'start: 3. stop: null. step: -1.'
224+
225+
s = seq2slice( 'end/2:', 5 );
226+
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
227+
// => 'start: 2. stop: 5. step: 1.'
228+
```
229+
230+
</section>
231+
232+
<!-- /.examples -->
233+
234+
<!-- Section to include cited references. If references are included, add a horizontal rule *before* the section. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
235+
236+
<section class="references">
237+
238+
</section>
239+
240+
<!-- /.references -->
241+
242+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
243+
244+
<section class="related">
245+
246+
</section>
247+
248+
<!-- /.related -->
249+
250+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
251+
252+
<section class="links">
253+
254+
[@stdlib/slice/ctor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/slice/ctor
255+
256+
</section>
257+
258+
<!-- /.links -->

0 commit comments

Comments
 (0)