Implement a multi-level digital recipe manager
Company: Ramp
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Take-home Project
Tests skills in data modeling and stateful class implementation, covering CRUD operations, case-insensitive string handling, recipe ID generation, list management, search and sort logic, and basic user/edit permissions.
Company: Ramp
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Take-home Project
Loading coding console...
Quick Answer: Tests skills in data modeling and stateful class implementation, covering CRUD operations, case-insensitive string handling, recipe ID generation, list management, search and sort logic, and basic user/edit permissions.
Input: [['add_recipe', 'Pasta', ['noodles', 'salt'], ['boil', 'mix']], ['get_recipe', 'recipe1'], ['update_recipe', 'recipe1', 'Cream Pasta', ['noodles', 'cream'], ['boil', 'stir']], ['get_recipe', 'recipe1'], ['delete_recipe', 'recipe1'], ['get_recipe', 'recipe1']]
Expected Output: ['recipe1', ['Pasta', 'noodles,salt', 'boil,mix'], True, ['Cream Pasta', 'noodles,cream', 'boil,stir'], True, []]
Explanation: Basic add, read, update, and delete flow.
Input: [['add_recipe', 'Soup', ['water'], ['boil']], ['add_recipe', 'soup', ['water', 'salt'], ['boil']], ['add_recipe', 'Salad', ['lettuce'], ['mix']], ['update_recipe', 'recipe2', 'SOUP', ['lettuce'], ['mix']], ['get_recipe', 'recipe2']]
Expected Output: ['recipe1', None, 'recipe2', False, ['Salad', 'lettuce', 'mix']]
Explanation: Recipe names are unique case-insensitively, both when adding and updating.
Input: [['add_recipe', 'Tea', [], []], ['get_recipe', 'recipe1'], ['delete_recipe', 'recipe2'], ['update_recipe', 'recipe3', 'X', [], []]]
Expected Output: ['recipe1', ['Tea', '', ''], False, False]
Explanation: Edge case with empty ingredient/step lists and missing recipe IDs.
Input: [['add_recipe', 'A', ['x'], ['s1']], ['delete_recipe', 'recipe1'], ['add_recipe', 'B', ['y'], ['z']], ['get_recipe', 'recipe2']]
Expected Output: ['recipe1', True, 'recipe2', ['B', 'y', 'z']]
Explanation: IDs continue increasing after deletions; they are not reused.
Input: [['add_recipe', 'Pancakes', ['flour', 'eggs', 'milk'], ['mix', 'cook']], ['add_recipe', 'Omelette', ['eggs', 'butter'], ['whisk', 'cook']], ['add_recipe', 'FrenchToast', ['bread', 'eggs', 'milk'], ['dip', 'fry']], ['search_recipes_by_ingredient', 'EGGS'], ['list_recipes', 'name']]
Expected Output: ['recipe1', 'recipe2', 'recipe3', ['recipe2', 'recipe1', 'recipe3'], ['recipe3', 'recipe2', 'recipe1']]
Explanation: Search sorts by ingredient count, then by recipe ID. Listing by name is case-insensitive.
Input: [['add_recipe', 'Soup', ['water'], ['boil']], ['add_recipe', 'soup', ['water', 'salt'], ['boil']], ['add_recipe', 'Salad', ['lettuce'], ['mix']], ['list_recipes', 'unknown'], ['search_recipes_by_ingredient', 'tomato']]
Expected Output: ['recipe1', None, 'recipe2', ['recipe2', 'recipe1'], []]
Explanation: Invalid sort key defaults to name sorting, and duplicate names are rejected.
Input: [['list_recipes', 'name'], ['search_recipes_by_ingredient', 'salt']]
Expected Output: [[], []]
Explanation: Edge case: empty manager.
Input: [['add_recipe', 'A', ['x'], ['s']], ['add_recipe', 'B', ['y'], ['s']], ['add_recipe', 'C', ['z', 'q'], ['s']], ['list_recipes', 'ingredient_count'], ['search_recipes_by_ingredient', 'Q']]
Expected Output: ['recipe1', 'recipe2', 'recipe3', ['recipe1', 'recipe2', 'recipe3'], ['recipe3']]
Explanation: Tie-breaking by recipe ID matters when ingredient counts are equal.
Input: [['add_recipe', 'Toast', ['bread'], ['toast']], ['add_user', 'u1'], ['edit_recipe', 'u1', 'recipe1', 'Buttered Toast', ['bread', 'butter'], ['toast', 'spread']], ['get_recipe', 'recipe1']]
Expected Output: ['recipe1', True, True, ['Buttered Toast', 'bread,butter', 'toast,spread']]
Explanation: A valid user can edit an existing recipe.
Input: [['add_recipe', 'Soup', ['water'], ['boil']], ['add_user', 'chef'], ['add_user', 'chef'], ['edit_recipe', 'ghost', 'recipe1', 'Hot Soup', ['water'], ['boil']], ['edit_recipe', 'chef', 'recipe2', 'Hot Soup', ['water'], ['boil']], ['get_recipe', 'recipe1']]
Expected Output: ['recipe1', True, False, False, False, ['Soup', 'water', 'boil']]
Explanation: Duplicate users are rejected, and missing user/recipe edits fail.
Input: [['add_recipe', 'Pie', ['fruit'], ['bake']], ['add_recipe', 'Cake', ['flour'], ['bake']], ['add_user', 'u1'], ['edit_recipe', 'u1', 'recipe2', 'PIE', ['flour'], ['bake']], ['get_recipe', 'recipe2']]
Expected Output: ['recipe1', 'recipe2', True, False, ['Cake', 'flour', 'bake']]
Explanation: Editing to a conflicting name is not allowed, even with different casing.
Input: [['add_recipe', 'Tea', [], []], ['add_user', 'u'], ['edit_recipe', 'u', 'recipe1', 'tea', [], []], ['get_recipe', 'recipe1']]
Expected Output: ['recipe1', True, True, ['tea', '', '']]
Explanation: Edge case: empty ingredients/steps and editing to the same logical name with different casing.
Input: [['add_recipe', 'Soup', ['water'], ['boil']], ['add_user', 'chef'], ['version_recipe', 'recipe1'], ['update_recipe', 'recipe1', 'Soup', ['water', 'salt'], ['boil', 'season']], ['edit_recipe', 'chef', 'recipe1', 'Tomato Soup', ['water', 'salt', 'tomato'], ['boil', 'blend']], ['version_recipe', 'recipe1'], ['rollback_recipe', 'recipe1', 1], ['get_recipe', 'recipe1'], ['version_recipe', 'recipe1']]
Expected Output: ['recipe1', True, [], True, True, ['1:Soup:water,salt:boil,season:system', '2:Tomato Soup:water,salt,tomato:boil,blend:chef'], True, ['Soup', 'water,salt', 'boil,season'], ['1:Soup:water,salt:boil,season:system', '2:Tomato Soup:water,salt,tomato:boil,blend:chef', '3:Soup:water,salt:boil,season:rollback']]
Explanation: A recipe has no history after add, gains versions after update/edit, and rollback appends a new version.
Input: [['version_recipe', 'recipe9'], ['rollback_recipe', 'recipe1', 1], ['add_recipe', 'A', [], []], ['version_recipe', 'recipe1'], ['rollback_recipe', 'recipe1', 1], ['add_user', 'u1'], ['edit_recipe', 'ghost', 'recipe1', 'B', [], []], ['update_recipe', 'recipe2', 'C', [], []]]
Expected Output: [[], False, 'recipe1', [], False, True, False, False]
Explanation: Edge cases: missing recipe, no history yet, missing user, and invalid update target.
Input: [['add_recipe', 'One', ['a'], ['s']], ['update_recipe', 'recipe1', 'PastName', ['a'], ['s1']], ['add_recipe', 'Other', ['b'], ['t']], ['update_recipe', 'recipe1', 'CurrentName', ['a'], ['s2']], ['update_recipe', 'recipe2', 'PastName', ['b'], ['t2']], ['rollback_recipe', 'recipe1', 1], ['get_recipe', 'recipe1']]
Expected Output: ['recipe1', True, 'recipe2', True, True, False, ['CurrentName', 'a', 's2']]
Explanation: Rollback can fail if the historical name now conflicts with another current recipe.
Input: [['add_recipe', 'Tea', [], []], ['update_recipe', 'recipe1', 'Herbal Tea', [], []], ['rollback_recipe', 'recipe1', 1], ['version_recipe', 'recipe1']]
Expected Output: ['recipe1', True, True, ['1:Herbal Tea:::system', '2:Herbal Tea:::rollback']]
Explanation: Rolling back to the same current state is still valid and creates a new version entry.