Nested Data Extractor
Problem Statement
Extract data from nested dictionaries and lists.
Background
Real-world data often has nested structures. Use chained indexing to access nested values:
data["users"][0]["name"]
Your Task
Write a function extract_info(data) that extracts specific values from a nested structure.
The data structure is:
{
"users": [
{"name": "...", "scores": [...]},
...
],
"metadata": {"count": ..., "version": ...}
}
Output Format
Return a dictionary with:
- "first_user": Name of first user
- "last_user": Name of last user
- "total_users": Value from metadata.count
- "all_names": List of all user names
- "first_user_avg": Average of first user's scores
Example:
Nested dict with users and metadata
{'first_user': 'Alice', 'last_user': 'Bob', 'total_users': 2, 'all_names': ['Alice', 'Bob'], 'first_user_avg': 87.67}Access users[0]['name'], users[-1]['name'], metadata['count'], etc.
Constraints:
- Data always has the structure shown
- At least one user exists
- Scores are non-empty lists of numbers
- Round average to 2 decimal places
1. Background Knowledge
Python dictionaries and lists form the backbone of handling nested data structures, which mimic real-world hierarchical data like JSON APIs or configuration files. Dictionaries (dict) store key-value pairs where values can be primitives (strings, numbers), lists, or other dictionaries, enabling chained indexing like data["users"]["name"] to drill down levels. Lists (list) maintain order and allow indexing by position (e.g., for first item), making them ideal for sequences like user arrays. Understanding mutability is key: dictionaries and lists are mutable, so operations like slicing (users[:] for copy) or len() prevent unintended side effects.
Accessing nested data requires safe navigation to avoid KeyError (missing key) or IndexError (out-of-bounds index). Concepts like iteration (for user in data["users"]) extract collections (e.g., all names), while built-ins like sum(scores) / len(scores) compute aggregates. These patterns build data extraction skills for larger tasks like API parsing or data processing pipelines, emphasizing readability via descriptive keys and list comprehensions (e.g., [user["name"] for user in users]).
2. Algorithm/Approach
Adopt a top-down traversal pattern: start from the root dictionary, access sub-structures by key/index, then apply targeted operations (indexing, iteration, aggregation) to build the output dictionary. Use functional decomposition—extract primitives (first/last via indices), iterate for lists (names), and compute derived values (average via math ops). This scales to deeper nesting by chaining accesses or recursion (though iteration suffices here). Validate structure implicitly via if checks or get() for robustness.
# Pattern sketch (not solution)
output = {}
users = data["users"] # Access list
output["first_user"] = users["name"] # Index access
output["all_names"] = [u["name"] for u in users] # Iteration + comprehension
3. Step-by-Step Strategy
- Access core structures: Retrieve data["users"] (list) and data["metadata"]["count"] (int) using chained indexing.
- Extract endpoints: Get first user name via users["name"]; last via users[-1]["name"] (negative index).
- Collect all names: Iterate over users list, appending each user["name"] to a list (use loop or comprehension).
- Compute average: Access users["scores"] (list of numbers), sum values, divide by length.
- Assemble output: Create dict with exact keys; return it. Test edge cases like empty lists.
4. Common Pitfalls
- Index/Key errors: Assuming keys exist—use data.get("users", []) or if "users" in data.
- Empty structures: len(users) == 0 crashes indexing; check if users: before or [-1].
- Type mismatches: Scores might not be numbers—ensure isinstance(scores, list); handle non-numeric via try/except.
- Floating-point precision: Average like sum(scores)/len(scores) gives float (e.g., 87.67); no rounding needed unless specified.
- Mutability: Modifying data accidentally—work with copies (e.g., users = data["users"][:]).
- Off-by-one: users[-1] for last is safer than users[len(users)-1].
5. Time & Space Complexity
- Time: O(n) where n= number of users (iteration for names + O(k) for first-user average, k= scores length; typically k≪n).
- Space: O(n) for all_names list (stores n strings); output dict is O(1) extra. Optimal for this extraction—no recursion or deep copies needed. Scales linearly with data size.