Concatenate Arrays
Problem Statement
Combine multiple NumPy arrays along different axes.
Background
- np.concatenate([arr1, arr2], axis=0): Stack vertically (default)
- np.concatenate([arr1, arr2], axis=1): Stack horizontally
- np.vstack(): Vertical stack
- np.hstack(): Horizontal stack
Your Task
Write a function concat_arrays(arr1, arr2) that returns a dictionary with:
- "vstack": Vertically stacked array as nested list
- "hstack": Horizontally stacked array as nested list
- "vstack_shape": Shape of vstack result as list
- "hstack_shape": Shape of hstack result as list
Output Format
Return a dictionary with exactly these four keys.
Example:
arr1 = [[1, 2], [3, 4]], arr2 = [[5, 6], [7, 8]]
{'vstack': [[1, 2], [3, 4], [5, 6], [7, 8]], 'hstack': [[1, 2, 5, 6], [3, 4, 7, 8]], 'vstack_shape': [4, 2], 'hstack_shape': [2, 4]}vstack: 2 rows + 2 rows = 4 rows. hstack: 2 cols + 2 cols = 4 cols
Constraints:
- Use np.vstack() and np.hstack()
- Both arrays will have compatible shapes
1. Background Knowledge
NumPy arrays (ndarray) are the fundamental data structure for numerical computing in Python, enabling efficient vectorized operations on multi-dimensional data. Array concatenation combines arrays along specified axes (dimensions), preserving data types while reshaping the output structure.
Key prerequisites:
- Array shapes: Represented as tuples (e.g., (2, 3) for 2 rows × 3 columns). Compatible shapes must match on non-concatenation axes.
- Axes: axis=0 (rows, vertical), axis=1 (columns, horizontal) for 2D arrays.
- Stacking functions:
| Function | Description | Shape Change Example |
|---|---|---|
| np.vstack() | Vertical stack (axis=0) | (m1,n) + (m2,n) → (m1+m2,n) |
| np.hstack() | Horizontal stack (axis=1) | (m,n1) + (m,n2) → (m,n1+n2) |
| np.concatenate() | General stacking | Same as above with explicit axis |
NumPy optimizes memory via contiguous arrays and views (zero-copy slicing), but stacking creates new arrays.
2. Algorithm Approach
This is a direct array manipulation problem using NumPy's built-in stacking primitives—no custom algorithms needed. The approach leverages:
- Vectorized concatenation: O(N) time where N is total elements, as NumPy uses C-level loops.
- Shape inference: Automatically compute output shapes from inputs.
- Type conversion: Convert ndarray → nested Python list via .tolist() for dictionary output.
No sorting, searching, or iteration required—pure functional composition.
3. Step-by-Step Strategy
- Validate inputs (implicit via constraints: shapes compatible).
- Vertical stack: vstack_result = np.vstack([arr1, arr2]).tolist()
- Horizontal stack: hstack_result = np.hstack([arr1, arr2]).tolist()
- Extract shapes: vstack_shape = list(np.vstack([arr1, arr2]).shape)
- Build dictionary: return {"vstack": vstack_result, "hstack": hstack_result, "vstack_shape": vstack_shape, "hstack_shape": list(np.hstack([arr1, arr2]).shape)}
Complete solution:
import numpy as np
def concat_arrays(arr1, arr2):
vstack_arr = np.vstack([arr1, arr2])
hstack_arr = np.hstack([arr1, arr2])
return {
"vstack": vstack_arr.tolist(),
"hstack": hstack_arr.tolist(),
"vstack_shape": list(vstack_arr.shape),
"hstack_shape": list(hstack_arr.shape)
}
4. Common Pitfalls
- Shape mismatch: vstack requires equal column counts; hstack requires equal row counts. Constraints guarantee compatibility, but test edge cases (e.g., 1D arrays treated as (n,) → row vectors).
- Array vs. list confusion: .tolist() converts ndarray to nested list; omitting it returns ndarray (fails output format).
- Axis defaults: np.concatenate defaults to axis=0; always use vstack/hstack for clarity.
- Memory copies: Stacking allocates new memory O(N)—irrelevant for constraints but scales poorly for huge arrays.
- 1D arrays: np.hstack([np.array([1,2]), np.array()]) fails (shapes (2,) vs (1,)); reshape if needed.
5. Time & Space Complexity
- Time: O(N) where N= total elements across both arrays. NumPy concatenation is linear in data size via contiguous memory copies.
- LaTeX: T(m1​n1​+m2​n2​)=O(N)
- Space: O(N) for new stacked arrays + O(d) for shapes (negligible, d= dimensions).
- Temporary arrays during stacking: O(N).
- Output dictionary: O(N) due to .tolist() copies.
- Scalability: Linear; bottlenecks only at memory bandwidth for N>109.