The central idea is to separate the definition of a transformation from its application. map should not inspect or reshape the array; instead, it records a function in an internal queue. The real work happens only when indexOf is called. At that point, each original value is passed through every queued function in order, and the scan stops as soon as the target value appears.
Each map call creates a fresh LazyArray instance. The new object shares the same read-only original array but owns a copied pipeline with the new function appended. This keeps earlier instances unaffected while allowing later queries to see the full chain. Sharing the original array is safe because no method ever mutates it.
For Example 2, consider arr = [10, 20, 30, 40, 50] with map(n -> n * 2) followed by map(n -> n * 3). When indexOf(240) runs, index 0 becomes , index 1 becomes , index 2 becomes , and index 3 becomes , so the answer is 3.
from typing import Callable, List, Tupleclass LazyArray: def __init__(self, arr: List[int]) -> None: self._original = arr[:] # clone the input array self._pipeline: Tuple[Callable[[int], int], ...] = () @classmethod def _from_parts( cls, original: List[int], pipeline: Tuple[Callable[[int], int], ...] ) -> "LazyArray": # Bypass __init__ so the original array is shared, not cloned again. instance = cls.__new__(cls) instance._original = original instance._pipeline = pipeline return instance def map(self, fn: Callable[[int], int]) -> "LazyArray": return LazyArray._from_parts(self._original, self._pipeline + (fn,)) def indexOf(self, target: int) -> int: for i, value in enumerate(self._original): for fn in self._pipeline: value = fn(value) if value == target: return i return -1import java.util.ArrayList;import java.util.List;import java.util.function.Function;class LazyArray { private final int[] original; private final List<Function<Integer, Integer>> pipeline; public LazyArray(int[] arr) { this.original = arr.clone(); // protect against external array changes this.pipeline = new ArrayList<>(); } private LazyArray(int[] original, List<Function<Integer, Integer>> pipeline) { this.original = original; this.pipeline = pipeline; } public LazyArray map(Function<Integer, Integer> fn) { List<Function<Integer, Integer>> extended = new ArrayList<>(pipeline); extended.add(fn); return new LazyArray(original, extended); } public int indexOf(int target) { for (int i = 0; i < original.length; i++) { int transformed = original[i]; // Apply every queued function in insertion order. for (Function<Integer, Integer> fn : pipeline) { transformed = fn.apply(transformed); } if (transformed == target) { return i; } } return -1; }}