@@ -128,4 +128,81 @@ public static function stableSort(array $data, callable $sortFn)
128128 // Undecorate each item and return the resulting sorted array
129129 return array_map (function ($ v ) { return $ v [0 ]; }, array_values ($ data ));
130130 }
131+
132+ /**
133+ * Creates a Python-style slice of a string or array.
134+ *
135+ * @param array|string $value Value to slice
136+ * @param int|null $start Starting position
137+ * @param int|null $stop Stop position
138+ * @param int $step Step (1, 2, -1, -2, etc.)
139+ *
140+ * @return array|string
141+ * @throws \InvalidArgumentException
142+ */
143+ public static function slice ($ value , $ start = null , $ stop = null , $ step = 1 )
144+ {
145+ if (!is_array ($ value ) && !is_string ($ value )) {
146+ throw new \InvalidArgumentException ('Expects string or array ' );
147+ }
148+
149+ return self ::sliceIndices ($ value , $ start , $ stop , $ step );
150+ }
151+
152+ private static function adjustEndpoint ($ length , $ endpoint , $ step )
153+ {
154+ if ($ endpoint < 0 ) {
155+ $ endpoint += $ length ;
156+ if ($ endpoint < 0 ) {
157+ $ endpoint = 0 ;
158+ }
159+ } elseif ($ endpoint >= $ length ) {
160+ $ endpoint = $ step < 0 ? $ length - 1 : $ length ;
161+ }
162+
163+ return $ endpoint ;
164+ }
165+
166+ private static function adjustSlice ($ length , $ start , $ stop , $ step )
167+ {
168+ if ($ step === null ) {
169+ $ step = 1 ;
170+ } elseif ($ step === 0 ) {
171+ throw new \RuntimeException ('step cannot be 0 ' );
172+ }
173+
174+ if ($ start === null ) {
175+ $ start = $ step < 0 ? $ length - 1 : 0 ;
176+ } else {
177+ $ start = self ::adjustEndpoint ($ length , $ start , $ step );
178+ }
179+
180+ if ($ stop === null ) {
181+ $ stop = $ step < 0 ? -1 : $ length ;
182+ } else {
183+ $ stop = self ::adjustEndpoint ($ length , $ stop , $ step );
184+ }
185+
186+ return [$ start , $ stop , $ step ];
187+ }
188+
189+ private static function sliceIndices ($ subject , $ start , $ stop , $ step )
190+ {
191+ $ type = gettype ($ subject );
192+ $ len = $ type == 'string ' ? strlen ($ subject ) : count ($ subject );
193+ list ($ start , $ stop , $ step ) = self ::adjustSlice ($ len , $ start , $ stop , $ step );
194+
195+ $ result = [];
196+ if ($ step > 0 ) {
197+ for ($ i = $ start ; $ i < $ stop ; $ i += $ step ) {
198+ $ result [] = $ subject [$ i ];
199+ }
200+ } else {
201+ for ($ i = $ start ; $ i > $ stop ; $ i += $ step ) {
202+ $ result [] = $ subject [$ i ];
203+ }
204+ }
205+
206+ return $ type == 'string ' ? implode ($ result , '' ) : $ result ;
207+ }
131208}
0 commit comments