Katkat

Parse and Format Arbitrarily Nested Tasks from CSV

StripeSoftware Engineer · Technical Screen

Last updated

Tests parsing RFC 4180-compliant CSV records containing hierarchical tasks and rendering an arbitrarily nested forest with proper tree line prefixes (`├── `, `└── `, and `│ `).

Problem Statement

You are given a CSV-formatted string representing a list of tasks. Each record contains three fields:

  • id: A unique string identifier for the task.
  • parent_id: The id of the parent task, or an empty string "" if the task is a root.
  • name: The display name of the task.

The input follows standard CSV rules (RFC 4180): fields containing commas or quotes are enclosed in double quotes, and literal quotes inside a quoted field are escaped as "".

Tasks may appear in any order in the CSV (a child task might appear before its parent). However, you must preserve the original input order when listing root tasks relative to each other, as well as sibling tasks under the same parent.

Your goal is to parse the CSV and return a formatted string representing the task hierarchy as an ASCII tree:

  • Root tasks have no indentation or branch symbol.
  • Sibling tasks must appear in their relative order of appearance in the input.
  • Non-last children use the branch prefix ├── .
  • The last child among its siblings uses the branch prefix └── .
  • Ancestor continuation lines use │ if the ancestor has subsequent siblings, or (four spaces) if it is the last child at that depth.

Interface

def format_task_tree(csv_data: str) -> str:
    pass

Input & Output Format

  • Input: csv_data, a single multiline string containing a header row id,parent_id,name followed by zero or more task rows.
  • Output: A string where each task name is printed on its own line with the appropriate tree formatting, separated by \n. If there are no tasks, return an empty string "".

Constraints

  • Total number of tasks: 0 <= N <= 2000.
  • Task IDs are unique non-empty alphanumeric strings.
  • parent_id is either empty or references an existing task id.
  • The hierarchy forms a valid forest (no cycles, no missing parents).
  • Tree depth can be arbitrary.
  • Standard library modules (such as Python's csv module) may be used for CSV parsing.

Examples

Example 1

Input:

id,parent_id,name
1,,Project Kickoff
2,1,Scope Definition
3,1,"Architecture, Design"
4,3,Diagrams
5,3,API Spec
6,1,Sign-off
7,,Follow-up Tasks
8,7,"Vendor ""A"" Sync"

Output:

Project Kickoff
├── Scope Definition
├── Architecture, Design
│   ├── Diagrams
│   └── API Spec
└── Sign-off
Follow-up Tasks
└── Vendor "A" Sync

Example 2 (Out of order tasks)

Input:

id,parent_id,name
child,root,Subtask B
root,,Main Task

Output:

Main Task
└── Subtask B

Edge Cases

  • Empty input or header-only CSV should return "".
  • Multiple root tasks with no children.
  • Deeply nested single-child chains.
  • Commas and escaped quotes within the task name.

Hints

Hint 1

Use a standard CSV reader (or handle RFC 4180 escaping) to extract rows into a map of `id -> name` and an adjacency list of `parent_id -> [child_ids]` while tracking root nodes in their order of appearance.

Hint 2

Since child rows may appear before their parent in the CSV, build the parent-to-children index after reading all rows rather than constructing the tree greedily during streaming.

Hint 3

When traversing recursively, pass along an accumulated prefix string or a list of booleans representing whether each ancestor is the last child in its sibling group.

Follow-up questions

  • How would you detect and report malformed input such as cycles, missing parent IDs, or duplicate task IDs?
  • If the CSV file is too large to fit entirely in memory, what changes to the input format or algorithm would be needed to stream and render the tree?
  • How would you extend the renderer if root nodes themselves needed to be visually connected as children of an invisible workspace root?