Sign in to run and submit your work
Reading is open to everyone. Running code and saving drafts need an account so your work is yours and comes back on your next visit.
or
CODE WORKSPACE
The warehouse's bulk-load endpoint rejects a request that carries more than a certain number of rows, and separately rejects one that carries more than a certain number of bytes. The loader currently sends one row per request, which works and takes six hours.
Write split_into_batches(rows, max_rows, max_bytes). Return the rows grouped into batches that respect both limits.
Function to write
split_into_batches(rows: list[dict], max_rows: int, max_bytes: int) -> list[list[dict]]A list of batches, each a list of rows, in the original order.
How to approach it
Track the open batch and its running byte total; decide to flush before you add the row.
Sample cases
+ 2 held back until you submit
both limits bite
The byte budget closes one batch early and the row limit closes another, with an oversized row in between.
Input
Argument 1
| id | bytes |
|---|---|
| r1 | 300 |
| r2 | 300 |
| r3 | 500 |
| r4 | 100 |
| r5 | 1500 |
| r6 | 200 |
Argument 2
3Argument 3
1000Returns
[
[
{
'id': 'r1',
'bytes': 300
},
{
'id': 'r2',
'bytes': 300
}
],
[
{
'id': 'r3',
'bytes': 500
},
{
'id': 'r4',
'bytes': 100
}
],
[
{
'id': 'r5',
'bytes': 1500
}
],
[
{
'id': 'r6',
'bytes': 200
}
]
]nothing to send
No rows means no batches — in particular, not one empty batch.
Input
Argument 1
[] (empty list)
Argument 2
3Argument 3
1000Returns
[] (empty list)
everything fits in one batch
Under both limits, the rows come back as a single batch rather than one batch each.
Input
Argument 1
| id | bytes |
|---|---|
| a | 10 |
| b | 20 |
Argument 2
10Argument 3
1000Returns
[
[
{
'id': 'a',
'bytes': 10
},
{
'id': 'b',
'bytes': 20
}
]
]Constraints
max_rows rows.max_bytes bytes, summed from each row's bytes field.max_bytes still has to be sent. It goes out in a batch of its own rather than being dropped or blocking every batch after it.bytes field, or one whose value is not a positive integer, counts as zero bytes.Worked example
With max_rows of 3 and max_bytes of 1000, the first three rows total 1100 bytes — so the batch closes after r1 and r2 at 600, and r3 opens the next one. That second batch takes r3 and r4 for 600 bytes, then r5 at 1500 would take it to 2100, so it closes there.
Row r5 is the interesting one: at 1500 bytes it is larger than the entire budget. The rule that fits every other row — start a new batch and add it there — would close the new batch immediately and add it again, forever. Guarding the check with 'only when the current batch is not empty' is what makes an oversized row go out alone instead of looping.
What this tests
Carrying two independent limits through one pass, and noticing that the rule which handles the normal case has a fixed point that never terminates. The oversized row is not an exotic case; every real sink has one.
split_into_batches(rows: list[dict], max_rows: int, max_bytes: int) -> list[list[dict]]Submit for review to find out what your query gets right, what it gets wrong, and how it compares with the best working query for this exercise.
This scenario runs a full workspace — editor, canvas and results side by side. It needs a laptop or desktop to be usable. Open this page on a bigger screen to start building.