Implement a custom list with iterator and map
Company: Snapchat
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates proficiency in data structures and generic collection implementation, specifically list operations, iterator semantics, and higher-order map functions.
Constraints
- Do not use built-in collection classes for the list's internal storage; resize a primitive/fixed array yourself.
- Indices are valid only when 0 <= index < size(); otherwise return the 'ERR' sentinel instead of raising.
- map(f) must return a NEW list and must not mutate the source.
- Elements may be any value (ints in the test driver); assume single-threaded use.
- Map function names: 'inc', 'double', 'square', 'neg', 'str'.
Examples
Input: ([('new','a'),('add','a',10),('add','a',20),('add','a',30),('size','a'),('get','a',1),('iterate','a')],)
Expected Output: [3, 20, [10, 20, 30]]
Explanation: Add three elements, then size()=3, get(1)=20, and iteration yields them in insertion order.
Input: ([('new','a'),('add','a',1),('add','a',2),('add','a',3),('set','a',1,99),('iterate','a'),('remove','a',0),('iterate','a'),('size','a')],)
Expected Output: [None, [1, 99, 3], 1, [99, 3], 2]
Explanation: set(1,99) returns None and overwrites index 1; remove(0) returns the removed 1 and shifts the rest left, leaving [99, 3] with size 2.
Input: ([('new','a'),('get','a',0),('remove','a',0),('set','a',0,5),('size','a'),('iterate','a')],)
Expected Output: ['ERR', 'ERR', 'ERR', 0, []]
Explanation: Edge case: every access on an empty list is out of range and returns the 'ERR' sentinel; size()=0 and iteration yields an empty list.
Input: ([('new','a'),('add','a',1),('add','a',2),('add','a',3),('add','a',4),('add','a',5),('add','a',6),('size','a'),('get','a',5),('iterate','a')],)
Expected Output: [6, 6, [1, 2, 3, 4, 5, 6]]
Explanation: Adding 6 elements past the initial capacity of 4 forces the backing array to grow; all elements survive in order and get(5)=6.
Input: ([('new','src'),('add','src',1),('add','src',2),('add','src',3),('map','src','dst','double'),('iterate','dst'),('iterate','src'),('map','src','sq','square'),('iterate','sq')],)
Expected Output: [None, [2, 4, 6], [1, 2, 3], None, [1, 4, 9]]
Explanation: map('double') produces a new list [2,4,6] while src is unchanged ([1,2,3]); a second map('square') on src yields [1,4,9], confirming map never mutates its source.
Input: ([('new','a'),('add','a',-5),('add','a',0),('add','a',7),('get','a',-1),('get','a',3),('remove','a',5),('iterate','a')],)
Expected Output: ['ERR', 'ERR', 'ERR', [-5, 0, 7]]
Explanation: Negative indices and indices >= size are both invalid and return 'ERR'; the list of [-5, 0, 7] is untouched.
Hints
- Back MyList with a fixed-size array plus an integer size; when size == capacity, allocate a new array of double the capacity and copy the elements over (this is exactly what ArrayList does under the hood).
- remove(index) must shift every element after index one slot to the left and then decrement size; clear the now-unused tail slot to avoid leaking references.
- For iteration, keep a cursor starting at 0; hasNext() is cursor < size() and next() returns data[cursor++]. In Python this is naturally a generator over indices 0..size-1.
- map should iterate the source in order, apply f, and add each result to a brand-new MyList — never write back into the source's array.