Difficulty: Easy | Acceptance: 86.60% | Paid: No Topics: N/A
Given a function fn, return a new function that allows fn to be called only once. The first call to the returned function should return the result of calling fn with the provided arguments. Any subsequent calls to the returned function should return the result of the first call without calling fn again.
- Examples
- Constraints
- Using Closure
- Using Function Property
- Using Wrapper Object
Examples
Input:
fn = (a,b,c) => (a + b + c), calls = [[1,2,3],[2,3,6]]
Output:
[{"calls":1,"value":6}]
Explanation:
const onceFn = once(fn)
onceFn(1,2,3) // 6
onceFn(2,3,6) // 6 (returns cached result)
Input:
fn = (a,b,c) => (a * b * c), calls = [[5,7,4],[2,3,6],[4,6,8]]
Output:
[{"calls":1,"value":140},{"calls":1,"value":140},{"calls":1,"value":140}]
Explanation:
const onceFn = once(fn)
onceFn(5,7,4) // 140
onceFn(2,3,6) // 140 (returns cached result)
onceFn(4,6,8) // 140 (returns cached result)
Constraints
- calls is a valid JSON array
- 1 <= calls.length <= 10
- 1 <= calls[i].length <= 100
- 2 <= JSON.stringify(calls).length <= 1000
Using Closure
Intuition Use a closure to store the result of the first call and a flag to track if the function has been called before.
Steps
- Create a variable
calledinitialized to false - Create a variable
resultto store the first call’s result - Return a function that checks if
calledis false - If not called, execute
fn, store result, setcalledto true - Return the stored result
python
def once(fn):
called = False
result = None
def inner(*args):
nonlocal called, result
if not called:
result = fn(*args)
called = True
return result
return innerComplexity
- Time: O(1) for first call, O(1) for subsequent calls
- Space: O(1) for storing called flag and result
- Notes: Clean and idiomatic approach using closure scope
Using Function Property
Intuition Attach a property directly to the returned function to track if it has been called and store the result.
Steps
- Create a new function that wraps
fn - Attach
hasCalledproperty initialized to false - Attach
cachedResultproperty initialized to undefined - On call, check
hasCalledproperty - If not called, execute
fn, store incachedResult, sethasCalledto true - Return
cachedResult
python
def once(fn):
def inner(*args):
if not hasattr(inner, 'has_called'):
inner.result = fn(*args)
inner.has_called = True
return inner.result
return innerComplexity
- Time: O(1) for first call, O(1) for subsequent calls
- Space: O(1) for storing properties on function
- Notes: Uses function as an object, slightly more verbose than closure
Using Wrapper Object
Intuition Use a wrapper object with internal state to manage the one-time call behavior.
Steps
- Create an object with
calledflag andresultstorage - Implement a callable method that checks state
- On first call, execute
fnand cache result - Return cached result on all calls
python
def once(fn):
class OnceWrapper:
def __init__(self, fn):
self.fn = fn
self.called = False
self.result = None
def __call__(self, *args):
if not self.called:
self.result = self.fn(*args)
self.called = True
return self.result
return OnceWrapper(fn)Complexity
- Time: O(1) for first call, O(1) for subsequent calls
- Space: O(1) for wrapper object state
- Notes: More object-oriented approach, useful for extending functionality