← Adobe Interview Insights

Adobe·Data Scientist·Technical Phone Screen·Junior

Junior
May 2023Remote

Summary

Technical screen for a Data Scientist role at Adobe covering basic SQL on app event data and a handful of Python one-liners. Nothing too wild, felt more like a warm-up round than a real filter.

Questions Asked (6)

Q1

Write a SQL query to count the number of distinct daily active users.

Product Analytics & MetricsData Modeling
Author's notes

Pretty bread and butter.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the definition of a daily active user (e.g., any user with at least one event per day) and the relevant table schema. Then write a query that groups by date and counts distinct user IDs, using a subquery or window function if needed to handle multiple events per user per day.

Pro tip: Mention that for large-scale data, using an approximate distinct count (e.g., HyperLogLog) can be more efficient, but confirm with stakeholders if exact counts are required. Also, consider time zone handling to ensure 'daily' aligns with business definitions.

1. Clarify requirements

Ask about the definition of 'active' (e.g., any event, specific event types) and the time zone for daily boundaries. Confirm the table structure and whether user IDs are unique per event.

2. Identify relevant columns

Determine the date/timestamp column and the user identifier column. Ensure you know how to extract the date part (e.g., DATE(event_time)) and handle potential nulls.

3. Write the core query

Use COUNT(DISTINCT user_id) grouped by date. For example: SELECT DATE(event_time) AS day, COUNT(DISTINCT user_id) AS dau FROM events GROUP BY 1 ORDER BY 1;

4. Handle edge cases and performance

Consider filtering out test users or bots, and discuss indexing or partitioning strategies for large datasets. If needed, use subqueries to pre-aggregate or window functions for rolling metrics.

5. Validate and interpret

Check results for anomalies (e.g., sudden spikes) and ensure the query aligns with business logic. Be prepared to explain how this metric informs product decisions.

Key Points to Mention

  • Definition of 'active user' and 'daily' (time zone, event types)
  • Use of COUNT(DISTINCT user_id) with GROUP BY date
  • Handling multiple events per user per day (distinct count ensures uniqueness)
  • Performance considerations: indexing, partitioning, approximate distinct counts
  • Data quality: filtering out internal/test users, handling nulls
  • Business context: how DAU ties to engagement and product health

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Write a SQL query to return the three most common event types from yesterday.

Product Analytics & MetricsData Modeling
Author's notes

Filter to yesterday, group by event_type, order by count descending, LIMIT 3.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the table schema and the definition of 'yesterday' (e.g., based on event timestamp and timezone). Then write a query that filters events to yesterday, groups by event type, counts occurrences, orders by count descending, and limits to 3.

Pro tip: Mention that you would use a date function like DATE(event_timestamp) = CURRENT_DATE - 1 to avoid timezone issues, and consider using a subquery or CTE for readability and to handle ties gracefully.

1. Clarify requirements

Ask about the table structure, column names, and how 'yesterday' is defined (e.g., based on event timestamp, timezone). Confirm if ties should be handled in a specific way.

2. Filter for yesterday's events

Use a WHERE clause to select only events from yesterday. For example, DATE(event_timestamp) = CURRENT_DATE - 1 or event_timestamp >= CURRENT_DATE - 1 AND event_timestamp < CURRENT_DATE.

3. Group and count

Group the filtered events by event_type and count the number of occurrences for each type using COUNT(*).

4. Order and limit

Order the results by the count in descending order and limit the output to the top 3 event types.

5. Handle ties (optional)

If there are ties at the third position, decide whether to include all tied types or use a deterministic tiebreaker (e.g., alphabetical order).

Key Points to Mention

  • Use of date functions to filter yesterday's data (e.g., CURRENT_DATE - 1, DATE_TRUNC).
  • Importance of timezone considerations when defining 'yesterday'.
  • Grouping by event_type and counting occurrences with COUNT(*).
  • Ordering by count descending and using LIMIT 3.
  • Handling ties at the cutoff (e.g., using RANK() or DENSE_RANK() if needed).
  • Writing clean, readable SQL with CTEs or subqueries for clarity.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Write a SQL query to list all users whose first recorded event was an install.

Data ModelingAlgorithms & Data Structures
Author's notes

This was the only one that made me pause.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a window function to rank events per user by timestamp, then filter for users whose earliest event is an install. Alternatively, use a subquery with MIN(event_time) and join back to the events table to identify the first event type.

Pro tip: Clarify assumptions about ties and event ordering—if multiple events share the same timestamp, specify how to break ties (e.g., by event priority or event_id). Also, mention that you'd validate the query on a sample to ensure correctness before running on full data.

1. Understand the schema and requirements

Identify the events table with columns like user_id, event_name, event_time (or timestamp). Confirm that 'first recorded event' means the earliest event_time per user, and that 'install' is a specific event_name.

2. Rank events per user by time

Use ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time ASC) to assign a rank to each event, ensuring the earliest event gets rank 1. Consider tie-breaking logic if timestamps can be equal.

3. Filter for first event being install

In an outer query or CTE, select users where the rank is 1 and event_name = 'install'. This yields the list of users whose first event was an install.

4. Alternative approach with subquery

If window functions are not preferred, use a subquery to find MIN(event_time) per user, then join back to the events table on user_id and event_time to get the event_name, and filter for 'install'.

5. Validate and optimize

Check for edge cases like users with no events, duplicate timestamps, or null values. Discuss indexing on (user_id, event_time) for performance and consider partitioning if the table is large.

Key Points to Mention

  • Use of window functions (ROW_NUMBER, RANK, DENSE_RANK) for ranking events per user.
  • Handling ties in event timestamps—e.g., using event_id or event priority as a secondary sort.
  • Performance considerations: indexing on (user_id, event_time) and avoiding full table scans.
  • Alternative approaches: subquery with MIN(event_time) and self-join, or using QUALIFY clause if supported.
  • Assumptions about data: event_name values, timestamp granularity, and whether 'install' is case-sensitive.
  • Validation steps: testing on sample data, checking for users with only one event, and ensuring no duplicate users in output.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Given a dictionary in Python, write code to invert it so that values become keys and keys become values.

Algorithms & Data Structures
Author's notes

Dict comprehension, {v: k for k, v in d.items()}.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the problem: whether the dictionary has unique values, what to do with duplicate values, and the expected output type. Then present a clean solution using a dictionary comprehension or a loop, and discuss handling edge cases like non-hashable values or duplicate values. Finally, analyze time and space complexity.

Pro tip: Mention that inverting a dictionary with duplicate values will collapse them into a single key, so you might need to decide whether to keep the last occurrence or group keys into lists. This shows you think about data integrity and real-world data issues.

1. Clarify requirements and constraints

Ask if values are unique and hashable, and whether the inverted dictionary should map to a single key or a list of keys for duplicates. Confirm the expected output format.

2. Choose an appropriate approach

For simple cases, use a dictionary comprehension: {v: k for k, v in d.items()}. For duplicates, use a loop with setdefault or defaultdict(list) to group keys.

3. Implement the solution

Write clean, readable code. If handling duplicates, iterate through items and append keys to lists. Ensure the code is efficient and Pythonic.

4. Test with edge cases

Test with empty dictionary, unique values, duplicate values, and non-hashable values (if applicable). Verify the output matches expectations.

5. Analyze complexity and discuss trade-offs

State that time complexity is O(n) and space complexity is O(n). Discuss the trade-off between simplicity and handling duplicates, and mention alternative approaches if needed.

Key Points to Mention

  • Dictionary comprehension for simple inversion: {v: k for k, v in d.items()}
  • Handling duplicate values: using defaultdict(list) or setdefault to group keys
  • Hashability requirement: values must be hashable to become keys
  • Time and space complexity: O(n) time and O(n) space
  • Edge cases: empty dictionary, duplicate values, non-hashable values
  • Pythonic code and readability

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

Remove duplicates from a Python list in a single line of code.

Algorithms & Data Structures
Author's notes

list(set(my_list)).

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: whether order must be preserved and if elements are hashable. Then present the idiomatic one-liner using dict.fromkeys() for order preservation, and mention alternative approaches like set() for unordered deduplication, explaining trade-offs.

Pro tip: Demonstrate awareness of Python version differences: dict.fromkeys() preserves insertion order in Python 3.7+, but for older versions, use OrderedDict. Also, note that set() is faster but loses order.

1. Clarify requirements

Ask if the order of elements must be preserved and if all elements are hashable. This determines the appropriate method.

2. Present the one-liner

For order preservation, use list(dict.fromkeys(lst)). For no order requirement, use list(set(lst)).

3. Explain the mechanism

Describe how dict.fromkeys() creates a dictionary with unique keys (since dict keys are unique) and then converts back to a list. For set(), explain that sets store unique elements.

4. Discuss trade-offs

Compare time complexity: set() is O(n) average but loses order; dict.fromkeys() is also O(n) and preserves order. Mention memory usage and hashability constraints.

5. Provide alternatives

If elements are unhashable, suggest using a loop with a seen list or using pandas if working with DataFrames, but note that a one-liner may not be possible.

Key Points to Mention

  • Order preservation: dict.fromkeys() maintains insertion order in Python 3.7+.
  • Time complexity: both set() and dict.fromkeys() are O(n) on average.
  • Hashability: elements must be hashable for both methods.
  • Python version: dict order preservation is guaranteed from Python 3.7.
  • Alternative: list(set(lst)) is simpler but unordered.
  • Edge cases: empty list, all duplicates, unhashable elements.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q6

Reverse a string in Python using a single line of code.

Algorithms & Data Structures
Author's notes

s[::-1].

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the problem: reversing a string means producing a new string with characters in reverse order. Then present the most Pythonic one-liner using slicing with a negative step, and briefly explain how it works and its time/space complexity.

Pro tip: Mention that slicing creates a new string and runs in O(n) time, which is optimal for this problem. Also note that for very large strings or streaming data, an iterative approach might be more memory-efficient, showing awareness of trade-offs.

1. Clarify requirements

Confirm that the input is a string and the output should be a new string with characters reversed. Ask if in-place reversal is needed (impossible for immutable strings) or if any constraints exist.

2. Present the one-liner

Write the solution: reversed_string = original_string[::-1]. Explain that the slice [::-1] starts from the end and steps backwards by 1.

3. Explain how it works

Break down the slice notation: [start:stop:step]. With start and stop omitted, it defaults to the whole string, and step -1 reverses the order.

4. Discuss complexity

State that the time complexity is O(n) because it must traverse all characters, and space complexity is O(n) for the new string. Mention that strings are immutable in Python, so a new string is necessary.

5. Consider alternatives and edge cases

Mention other one-liners like ''.join(reversed(s)) and note that they are also O(n) but slightly less efficient due to join overhead. Handle edge cases: empty string, single character, Unicode strings.

Key Points to Mention

  • Python's slice notation with negative step
  • Strings are immutable, so reversal creates a new string
  • Time and space complexity: O(n)
  • Alternative one-liners: ''.join(reversed(s))
  • Edge cases: empty string, single character, Unicode
  • Readability and Pythonic style

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.