Process Shopping Records, Promotions, and Display Order
Reported by candidates from Instacart's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Instacart reported this one in September 2026, and the title sounds scarier than it is. Strip the story and it's string parsing, a per-row min over a handful of promotions, then a stable sort on two keys. No graph, no DP. The risk is the pile of small rules: malformed rows, half-up rounding, the buy-X-get-Y group math. If you blank on the details during the OA, StealthCoder runs invisibly on your desktop as a safety net. But the logic is very doable if you read the spec slowly.
The problem
You receive shopping records in rows. A valid row has exactly six pipe-separated fields: sku|name|quantity|priceCents|aisle|frozen. The sku, name, and aisle fields are non-empty ASCII text without pipes; quantity and priceCents are nonnegative integers; and frozen is exactly true or false. Ignore every malformed row and every row with a negative quantity or price. A valid promotion is one of sku|PERCENT|p, where 0 <= p <= 100, or sku|BUY_X_GET_Y|x|y, where x and y are positive. Ignore malformed promotions. For a percentage promotion, discount the full row price and round half up to the nearest cent. For a buy-X-get-Y-free promotion, each complete group of x + y units charges for only x units. Apply at most one promotion to each row, choosing the lowest valid row price; the undiscounted price is always available. Duplicate SKUs remain independent rows. Return an array whose first entries are units=<totalQuantity>, base=$<dollars.cents>, and promoted=$<dollars.cents>. Append every valid original row after the summaries, with non-frozen rows first and frozen rows last. Within each group, sort by ascending aisle; exact aisle ties retain input order. Function processShoppingRecords(rows: String[], promotions: String[]) → String[] Examples Example 1 rows = ["a100|apple|6|123|produce|false","i200|ice cream|2|450|frozen|true","bad|row"] promotions = ["a100|PERCENT|10","a100|BUY_X_GET_Y|2|1"] return = ["units=8","base=$16.38","promoted=$13.92","a100|apple|6|123|produce|false","i200|ice cream|2|450|frozen|true"] The malformed row is ignored. Apples cost 738 cents normally, 664 cents after 10% off, and 492 cents under buy-two-get-one-free, so the cheapest promotion wins. Ice cream has no promotion. The non-frozen row precedes the frozen row. Example 2 rows = ["b|bread|1|199|bakery|false","m|milk|3|101|dairy|false","p|peas|0|75|a01|true"] promotions = ["m|PERCENT|50","m|BUY_X_GET_Y|1|1","m|PERCENT|101"] return = ["units=4","base=$5.02","promoted=$3.51","b|bread|1|199|bakery|false","m|milk|3|101|dairy|false","p|peas|0|75|a01|true"] Half of milk's 303-cent row price rounds up to 152 cents, while buy-one-get-one-free charges 202 cents. The invalid 101% promotion is ignored. The zero-quantity peas row is valid and appears in the frozen group. Constraints 0 <= rows.length, promotions.length <= 100000. The combined length of all row and promotion strings is at most 1000000. Valid sku, name, and aisle fields contain printable ASCII characters other than |; sku and aisle contain no whitespace. Valid quantities and prices are from 0 through 1000000000. At most 20 valid promotions share one SKU. The total quantity, base price, promoted price, and every intermediate product fit in a signed 64-bit integer.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Here's what it reduces to. Parse each row with a strict validator: exactly six fields, non-empty sku, name and aisle, integer quantity and price, frozen being true or false. Group valid promotions by SKU in a hash map. For each row, row price is quantity times priceCents. Percent price is price minus the discount, rounded half up, so use integer math: (price * (100 - p) + 50) / 100. Buy-X-get-Y charges (q / (x+y)) * x + (q % (x+y)) units, times unit price. Take the min with the undiscounted price. Sum units, base and promoted. Then stable-sort valid rows by the frozen flag, then aisle. The pitfalls are float rounding, treating a zero-quantity row as invalid, and an unstable sort. If you freeze live, StealthCoder is the hedge for the OA.
The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.
You can drill Process Shopping Records, Promotions, and Display Order cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Instacart's OA.
Instacart reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Process Shopping Records, Promotions, and Display Order FAQ
What's the actual trick in the Instacart shopping records problem?+
There isn't one clever trick. It's careful parsing plus a stable sort. Validate each row strictly, compute the cheapest of up to 21 prices per row, and sort by frozen flag then aisle. Most failures come from edge cases in validation and rounding, not from the algorithm.
How do I round half up to the nearest cent without floats?+
Use integer math. For a percent promotion p on a total price T, compute (T * (100 - p) + 50) / 100 with integer division. That gives half up on the discounted price. Values fit in 64-bit per the constraints, so you won't overflow.
How do I compute buy X get Y free correctly?+
Each full group of x + y units charges for x units. So paid units = (q / (x + y)) * x + (q % (x + y)). Wait, the leftover units are all charged, since they don't form a full group. Multiply paid units by the unit price. Check it against example 1: 6 units with 2 and 1 gives 4 paid, 492 cents.
How do I keep the sort stable for aisle ties?+
Use a stable sort, or sort on a composite key of frozen flag, aisle, and original index. Frozen false comes first, then aisle ascending, and ties keep input order. Compare aisles as plain ASCII strings, not numerically, since values like a01 appear.
How should I prepare in 48 hours for this kind of OA?+
Write a clean parser with split on the pipe character, and watch for trailing empty fields that a lazy split drops. Hand-test both examples, including the invalid 101 percent promotion and the zero-quantity row. Then test an empty input. That covers most of the traps.