Batch and Pad Variable-Length Vectors with Optional Final-Batch Dropping
SiemensMachine Learning Engineer · Technical ScreenLast updated
Implement an ordered data pipeline function that partitions variable-length numerical sequences into batches, applies batch-local right padding, handles empty vectors, and optionally discards incomplete final batches.
Problem Statement
In machine learning pipelines processing sequential telemetry, physical sensor logs, or embeddings, inputs often arrive as ordered sequences of variable lengths. Prior to feeding these inputs into tensor-based models, they must be organized into batches and padded.
Write a function batch_and_pad that takes a list of variable-length floating-point vectors and produces a list of padded 2D batches according to the following rules:
- Batching: Partition the ordered input sequences into contiguous batches of size
batch_size. - Incomplete Final Batch: If
drop_lastisTrueand the final batch contains strictly fewer thanbatch_sizeelements, discard that final batch. Ifdrop_lastisFalse, retain it. - Batch-Local Right Padding: For each batch, determine the maximum length
L_maxamong all sequences within that specific batch. Pad each sequence on the right withpad_valueuntil its length equalsL_max. - Empty Sequence Handling: If an input sequence is empty (
[]), it should still be treated as a valid vector of length0. If an entire batch contains only empty sequences,L_maxis0, and each sequence in that batch remains empty.
Function Signature
def batch_and_pad(
sequences: list[list[float]],
batch_size: int,
pad_value: float = 0.0,
drop_last: bool = False
) -> list[list[list[float]]]:
pass
Examples
Example 1
sequences = [[1.0, 2.0], [3.0], [], [4.0, 5.0, 6.0], [7.0]]
batch_size = 2
pad_value = 0.0
drop_last = False
output = batch_and_pad(sequences, batch_size, pad_value, drop_last)
# Output:
# [
# [[1.0, 2.0], [3.0, 0.0]],
# [[0.0, 0.0, 0.0], [4.0, 5.0, 6.0]],
# [[7.0]]
# ]
Explanation:
- Batch 1 has vectors of lengths 2 and 1 (
L_max = 2).[3.0]is right-padded with one0.0. - Batch 2 has vectors of lengths 0 and 3 (
L_max = 3).[]is right-padded with three0.0s. - Batch 3 contains the remaining element
[7.0]. Sincedrop_last=False, it is kept.
Example 2
sequences = [[1.0, 2.0], [3.0], [], [4.0, 5.0, 6.0], [7.0]]
batch_size = 2
pad_value = -1.0
drop_last = True
output = batch_and_pad(sequences, batch_size, pad_value, drop_last)
# Output:
# [
# [[1.0, 2.0], [3.0, -1.0]],
# [[-1.0, -1.0, -1.0], [4.0, 5.0, 6.0]]
# ]
Explanation: The final batch containing only [7.0] has size 1 (< batch_size), so it is dropped.
Constraints
0 <= len(sequences) <= 10^50 <= len(seq) <= 5 * 10^3for each sequenceseqinsequences- Total number of elements across all sequences
<= 10^6 1 <= batch_size <= 10^4pad_valueis a finite float.
Hints
Hint 1
Slice the input list in strides of `batch_size` and verify whether the final slice should be skipped based on `drop_last` and slice length.
Hint 2
For each batch, compute `L_max = max((len(seq) for seq in batch), default=0)` to safely handle batches where all sequences are empty.
Hint 3
Construct each padded vector without mutating the original input vectors, appending `[pad_value] * (L_max - len(seq))` to each sequence.
Follow-up questions
- How would you refactor this into a Python generator to stream batches lazily without loading the entire dataset into memory?
- How would you modify the output to return both padded sequences and corresponding binary padding masks (e.g., 1 for real tokens, 0 for pad tokens)?
- If sequence lengths vary wildly (e.g., length 2 vs length 2000), how could length-based bucketing or sorting reduce wasted padding compute while preserving epoch-level randomization?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.