Filter, Sort, and Deduplicate Scheduled Tasks
Reported by candidates from Rippling's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Rippling reported this one in September 2026, and the detail that trips people is Example 3: dedup runs before the completed filter, so a finished task can eat an active duplicate and leave you with an empty list. It's a sorting problem wearing a tree costume. Parallel arrays, a parent ID forest, and three phases that must run in exact order. You've got a 2 * 10^5 input size, so sloppy recursion or repeated scans will hurt. Below is the pattern, the trap, and what to do if your head goes blank mid-assessment. StealthCoder is the safety net if that happens.
The problem
A batch contains tasks described by parallel arrays. Task i has the unique ID taskIds[i], description descriptions[i], due date dueDates[i], priority priorities[i], completion flag completed[i], and parent ID parentIds[i]. An empty parent ID marks a root task. Return the task IDs after applying these phases in order: Deduplicate: Tasks with the same exact pair (description, due date) are duplicates. Keep only the first input occurrence of each pair. Filter: Remove every retained task whose completion flag is true. A task also survives only if its parent survives, so removing any task removes its entire descendant subtree. Order: Compare retained tasks by higher priority first, then earlier due date, then earlier retained input position. Expand the hierarchy: Sort the root tasks and every sibling list with that comparison. Emit each root in order, followed immediately by its complete retained subtree in preorder. Return each surviving task ID exactly once. Function orderHierarchicalTasks(taskIds: String[], descriptions: String[], dueDates: long[], priorities: int[], completed: boolean[], parentIds: String[]) → String[] Examples Example 1 taskIds = ["p1","c1","dup","p2","c2","done","done-child"] descriptions = ["Launch","Docs","Launch","Payroll","Tax","Archive","Cleanup"] dueDates = [10,8,10,5,4,1,2] priorities = [2,5,9,3,7,10,9] completed = [false,false,false,false,false,true,false] parentIds = ["","p1","","","p2","","done"] return = ["p2","c2","p1","c1"] dup shares (Launch, 10) with the earlier task p1, so dup is discarded. Completed task done is removed together with descendant done-child. Priority places root p2 before p1, and each child follows its parent. Example 2 taskIds = ["root2","root","a","b","grand"] descriptions = ["Other","Plan","Build","Review","Test"] dueDates = [2,20,10,5,1] priorities = [6,1,5,4,9] completed = [false,false,false,false,false] parentIds = ["","","root","root","a"] return = ["root2","root","a","grand","b"] Root root2 has higher priority than root. Inside root's subtree, a precedes sibling b; preorder emits nested task grand immediately after a before returning to b. Example 3 taskIds = ["a","b","c"] descriptions = ["Sync","Sync","Done"] dueDates = [1,1,2] priorities = [1,9,5] completed = [true,false,true] parentIds = ["","",""] return = [] Deduplication happens before filtering, so completed task a survives the duplicate pair and active task b is discarded. Filtering then removes a and c. Constraints 0 <= taskIds.length <= 2 * 10^5. All six arrays have the same length. Task IDs are unique strings containing 1 to 40 ASCII letters, digits, hyphens, or underscores. Descriptions contain 1 to 100 visible ASCII characters; duplicate matching is exact and case-sensitive. Each due date fits in a signed 64-bit integer, and each priority fits in a signed 32-bit integer. Each parent ID is empty or equals another input task ID, and the parent relation forms a forest.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is to run the phases literally. First, walk the input once with a hash set keyed on (description, dueDate) and keep only the first occurrence. Second, drop completed tasks, then drop anything whose parent was removed. Don't forget a parent can be removed by dedup too, so check survival against the retained set, not the original input. Third, build a children list per parent ID, sort each sibling list and the roots with the comparator: priority descending, due date ascending, retained input index ascending. Finally, emit via preorder DFS. With 2 * 10^5 tasks, a deep chain can blow the recursion stack, so use an explicit stack and push children in reverse order. The common pitfall is filtering before deduplicating, which Example 3 punishes. If you freeze on the iterative preorder or the comparator on the live OA, StealthCoder is the hedge that gives you a working solution on screen.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Filter, Sort, and Deduplicate Scheduled Tasks 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. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Rippling's OA.
Rippling reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Filter, Sort, and Deduplicate Scheduled Tasks FAQ
What's the trick in the Rippling task ordering problem?+
Apply the phases in the stated order: dedup, then filter with subtree removal, then sort, then preorder expansion. Most wrong answers swap dedup and filter. Example 3 exists to catch exactly that, since the completed duplicate wins and the active one is discarded.
How hard is this problem really?+
Medium. No exotic algorithm is needed. It's a hash set, a children map, a comparator, and a DFS. The difficulty is carefulness with phase order and tie-breaking, not insight. Expect to lose points on edge cases, not on the core idea.
How do I handle removing a whole descendant subtree?+
Build the retained set after dedup and the completed filter. Then a task survives only if it's a root or its parent survives. Easiest is to do the DFS from retained roots over retained children only, so orphaned descendants are never reached.
Will recursion break on large inputs?+
It can. With up to 2 * 10^5 tasks, a long parent chain makes recursive preorder risky in many languages. Use an explicit stack, pushing sorted children in reverse so the highest-ranked child pops first. That keeps the preorder correct.
How do I prepare for this in 48 hours?+
Write a multi-key comparator from scratch, practice building a children map from parent IDs, and code an iterative preorder. Then run all three examples by hand, especially the empty-result one. That covers nearly everything this problem tests.