Array Slicing
Problem Statement
Extract portions of a NumPy array using slicing syntax.
Background
NumPy slicing: arr[start:stop:step]
- start: Starting index (inclusive, default 0)
- stop: Ending index (exclusive)
- step: Step size (default 1)
Your Task
Write a function slice_array(arr) that returns a dictionary with:
- "first_three": First 3 elements as list
- "last_three": Last 3 elements as list
- "every_other": Every other element as list
- "reversed": Reversed array as list
Output Format
Return a dictionary with exactly these four keys.
Example:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
{'first_three': [0, 1, 2], 'last_three': [7, 8, 9], 'every_other': [0, 2, 4, 6, 8], 'reversed': [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]}[:3] for first 3, [-3:] for last 3, [::2] for every other, [::-1] for reverse
Constraints:
- Array will have at least 3 elements
- Use slicing syntax arr[start:stop:step]
1. Background Knowledge
NumPy arrays are the foundational data structure for numerical computing in Python, enabling efficient vectorized operations on multi-dimensional data. Slicing extracts portions of arrays using the syntax arr[start:stop:step], where:
- start: Inclusive starting index (default: 0)
- stop: Exclusive ending index (default: array length)
- step: Increment between indices (default: 1, negative for reverse)
Slices create views (shallow copies) by default, sharing memory with the original array for efficiency—modifications affect the source. This contrasts with indexing, which often returns copies. Prerequisites: Basic Python lists/arrays and NumPy ndarray creation via np.array().
2. Algorithm Approach
Use pure slicing operations without loops or conditionals, leveraging NumPy's vectorized indexing:
- Prefix slicing: arr[:3] for first n elements.
- Suffix slicing: arr[-3:] for last n elements (negative indices count from end).
- Strided slicing: arr[::2] for every kth element.
- Reversal: arr[::-1] (step = -1).
Convert slices to lists via .tolist() for dictionary output. This exploits NumPy's O(1) slice creation time due to view semantics.
3. Step-by-Step Strategy
- Access input: Function receives arr (1D NumPy array, length ≥3).
- Extract slices:
- "first_three": arr[:3]
- "last_three": arr[-3:]
- "every_other": arr[::2] (starts at 0, step 2)
- "reversed": arr[::-1]
- Convert to lists: Apply .tolist() to each slice.
- Build dictionary: Return {"first_three":..., "last_three":...,...}.
- Test: Verify with sample [0,1,2,3,4,5,6,7,8,9].
import numpy as np
def slice_array(arr):
return {
"first_three": arr[:3].tolist(),
"last_three": arr[-3:].tolist(),
"every_other": arr[::2].tolist(),
"reversed": arr[::-1].tolist()
}
4. Common Pitfalls
- Forgetting .tolist(): Slices return ndarray, not list—dictionary requires lists.
- Index errors: Constraints guarantee ≥3 elements, but arr[-3:] fails on length=2.
- Modifying views: slice_arr = arr[:3]; slice_arr = 99 alters original arr.
- Step confusion: ::2 skips every other (even indices); 1::2 for odds.
- Multi-D arrays: Problem assumes 1D; higher dims need arr[0, :3] etc.
- Inclusive/exclusive mix-up: stop is exclusive (arr[:3] gets indices 0,1,2).
5. Time & Space Complexity
- Time: O(n) where n=len(arr)—slicing is O(1) (view creation), but .tolist() copies data: first_three/last_three = O(1), every_other = O(n/2), reversed = O(n).
- Space: O(n) worst-case for full copies in lists; slices themselves use O(1) extra (views share memory).
Total: Θ(n) time and space, optimal for output size. No loops ensure vectorized efficiency.