Coding questions · Siemens
Batch and Pad Variable-Length Vectors with Optional Final-Batch Dropping
Build an ordered vector data pipeline with batch-local right padding, empty-vector handling, and optional dropping of the final incomplete batch.
Implement a deterministic data pipeline that groups variable-length integer vectors into batches, pads each retained batch, and optionally drops the final incomplete batch.
The exercise models three responsibilities: create_data_iterator groups vectors in input order, pad_vector_collate right-pads one batch to its longest vector, and run_data_pipeline returns the collected batches. Only the final function is the console entry point; internal helper organization is up to you.
Function Signature
run_data_pipeline(vectors: list[list[int]], batch_size: int, pad_value: int, drop_last: bool) -> list[list[list[int]]]
Rules
- Read vectors in their original order without shuffling or mutation.
- Form consecutive groups of
batch_sizevectors. - If the final group contains fewer vectors and
drop_lastis true, discard that entire group. Otherwise retain it. - For each retained group, let
Lbe the greatest original vector length in that group. Appendpad_valueto each vector until its length isL. - Padding is batch-local, not based on the longest vector in the whole dataset.
- Empty vectors are valid. A retained batch containing only empty vectors contains the same number of empty vectors after padding.
These padding direction, pad-value input, ordering, and incomplete-batch rules are explicit conventions for this exercise.
Output
Return the padded batches in input order. Return [] if no batch is retained.
Constraints
0 <= len(vectors) <= 10000.1 <= batch_size <= 1000.0 <= len(vector) <= 1000for each vector.- Vector elements and
pad_valueare integers in[-1000000, 1000000]. - The total number of input elements and the total number of elements after padding are each at most
1000000. - All input arguments are valid.
Examples
Input: vectors = [[1,2],[3],[],[4,5,6],[7]], batch_size = 2, pad_value = 0, drop_last = false
Output: [[[1,2],[3,0]],[[0,0,0],[4,5,6]],[[7]]]
With the same arguments except drop_last = true, output: [[[1,2],[3,0]],[[0,0,0],[4,5,6]]]
Input: vectors = [[],[]], batch_size = 2, pad_value = -1, drop_last = true
Output: [[[],[]]]
Input: vectors = [], batch_size = 3, pad_value = 0, drop_last = false
Output: []
Batch and Right-Pad Variable-Length Vectors
Implement a deterministic data pipeline that groups variable-length integer vectors into batches, pads each retained batch, and optionally drops the final incomplete batch.
The exercise models three responsibilities: grouping the vectors in input order, right-padding one batch to its longest vector, and returning the collected batches. Only run_data_pipeline is the console entry point; how you organize any internal helpers is up to you.
Rules
- Read the vectors in their original order, without shuffling or mutating them.
- Form consecutive groups of
batch_sizevectors: the firstbatch_sizevectors, then the nextbatch_size, and so on. - If the final group contains fewer than
batch_sizevectors anddrop_lastis true, discard that entire group. Otherwise retain it. - For each retained group, let
Lbe the greatest original vector length in that group. Appendpad_valueto each vector of the group until its length is exactlyL. Padding is appended on the right, never prepended. - Padding is batch-local:
Lis the longest vector of that group only, not the longest vector of the whole dataset. - Empty vectors are valid. A retained batch containing only empty vectors has
L = 0, so it contains the same number of empty vectors after padding.
These padding-direction, pad-value, ordering, and incomplete-batch rules are explicit conventions of this exercise.
Output
Return the padded batches as a list of batches, in input order. Return [] if no batch is retained.
Every value that crosses the boundary is an element or pad_value in [-1000000, 1000000]; no value can exceed 2^31 - 1, so Java int and C++ int are sufficient (no long/long long is needed).
Examples
Example 1: vectors = [[1, 2], [3], [], [4, 5, 6], [7]], batch_size = 2, pad_value = 0, drop_last = False.
Output: [[[1, 2], [3, 0]], [[0, 0, 0], [4, 5, 6]], [[7]]].
The groups are [[1,2],[3]] with L = 2, [[],[4,5,6]] with L = 3, and the final short group [[7]] with L = 1, which is retained because drop_last is false. With the same arguments except drop_last = True, the output is [[[1, 2], [3, 0]], [[0, 0, 0], [4, 5, 6]]] because the final group holds fewer than batch_size vectors.
Example 2: vectors = [[], []], batch_size = 2, pad_value = -1, drop_last = True.
Output: [[[], []]]. The single group is full, its greatest length is 0, so no padding is appended.
Hints
- Only one group can ever be incomplete. Which one is it, and what does that tell you about when the drop_last test actually has to run?
- The pad target L is defined by the original lengths inside a single group, so decide L before you write any padding and make sure a group cannot see padding produced for an earlier group.
- Work through the cases the rules single out: an empty vectors list, a batch whose vectors are all empty, and an empty vector sitting next to a long one in the same batch.
Approach
Algorithm: walk the input with a cursor that advances by batch_size, so the slice [start, min(start + batch_size, n)) is the next consecutive group in input order. Because the cursor advances by a fixed stride from index 0, only the last group can contain fewer than batch_size vectors; when that happens and drop_last is true, the group is skipped entirely and nothing derived from it is emitted. For a retained group, a single pass computes L, the greatest original length in that group, and a second pass copies each vector into a fresh list and appends pad_value until its length equals L.
Invariant: after processing a group, the output holds exactly one padded batch per retained group seen so far, in input order, and every vector inside a retained batch has the same length L computed from the original lengths of that group only. Using original lengths (collected before any padding is written) is what makes the padding batch-local: a long vector in one group can never influence L of another group, and copying each vector before appending means the input is never mutated, so a later group cannot observe padding added to an earlier one.
Correctness: the groups partition the input into consecutive runs in order, which matches the grouping rule; the drop test matches the incomplete-batch rule; appending to the end of the copy is right-padding; and the loop emits batches in the order the groups were produced, which is input order.
Edge cases: an empty vectors list produces no iteration and returns []; a batch_size at least as large as the number of vectors produces one group that is incomplete unless the sizes match exactly, so drop_last true can legitimately return []; a group of only empty vectors has L = 0, so the padding loop appends nothing and the empty vectors stay empty; an empty vector inside a group with a longer vector becomes L copies of pad_value; pad_value may be negative, zero, or equal to values already present, and none of those is special-cased; batch_size = 1 makes every group full and self-maximal so no padding occurs.
- Time complexity: O(N + P), where N is the total number of input elements and P is the total number of elements after padding (each vector is scanned for its length and copied once, then padded to its batch maximum).
- Space complexity: O(P) for the returned batches (O(1) auxiliary space beyond the output).