2804. Array Prototype ForEach
Problem Description
The problem requires the creation of a custom forEach
method that can be applied to all arrays. In JavaScript, the forEach
method is a built-in function that executes a provided function once for each array element. However, this custom method should be written without using the native .forEach
or other built-in array methods.
The custom forEach
method needs to accept two parameters:
callback
: a function that you want to execute for each element in the array.context
: an object that can be referred to asthis
within the scope of thecallback
function.
The callback
function itself should have access to three arguments:
currentValue
: the value of the array element in the current iteration.index
: the index of the current array element.array
: the entire array that theforEach
is being executed upon.
The essence of this problem is to enhance the array prototype inside JavaScript, ensuring that this functionality is available on all arrays within that context.
Intuition
The intuition is to replicate the behavior of the built-in forEach
functionality manually. We want to achieve three key tasks:
- Iterate through each element of the array – we can do this via a for loop that starts at the beginning of the array (index 0) and continues to the end (length of the array).
- During each iteration, execute the
callback
function with the proper arguments – we can call thecallback
function withcurrentValue
,index
, andarray
. - Respect the
context
in whichcallback
is executed if provided – we can use thecall
method on thecallback
function to set thethis
value explicitly to thecontext
passed as a parameter.
The solution doesn't return anything because the purpose of forEach
is to execute side effects rather than compute and return a value. The forEach
method is more about doing something with each array element, like modifying the array or using the elements for some other side effectful operations. This implementation fits the requirement which is to execute the provided function for each of the array's elements with the given context.
Solution Approach
The implementation of the custom forEach
method makes use of JavaScript's prototypal inheritance. By appending a new function to Array.prototype
, we ensure that all arrays inherit this method.
Here is the step-by-step breakdown of the approach:
-
We start by adding a new function to
Array.prototype
namedforEach
. This means that every array created in this JavaScript environment will now have access to this customforEach
method. -
Our
forEach
function takes in two parameters:callback
andcontext
. Thecallback
is a function that we want to call with each element of the array. Thecontext
is optional and is used to specify the value ofthis
inside the callback function when it is called. -
We make use of a simple for loop to iterate over the array. The initial index is set to 0, and we loop through until we reach the end of the array, denoted by
this.length
, because within this function,this
refers to the array upon which theforEach
method was called. -
For each iteration, we use the
call
method of thecallback
function to execute it. Thecall
method is a built-in JavaScript method that allows us to call a function with an explicitly setthis
value – in this case, thecontext
parameter. Ifcontext
isundefined
, the value ofthis
inside the callback will default to the global object, which is the default behavior in a browser, or toundefined
in strict mode. -
The
callback
function is called with three arguments: the current element value (this[i]
), the current index (i
), and the array itself (this
). This matches the standardforEach
method's signature.
The code does not include any complex algorithms, data structures, or patterns—it is a straightforward iteration using a for loop and function calls, sticking closely to the requirements of how the built-in forEach
is expected to function.
The beauty of this approach is in its simplicity and direct manipulation of the Array.prototype
to achieve the desired effect across all arrays within the scope of execution.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's consider an example where we have an array of names and we want to print each name to the console with a greeting. The array is ['Alice', 'Bob', 'Charlie']
.
Here's a breakdown of how we could use our custom forEach
method to accomplish this:
-
First, we'd set up our custom
forEach
method by extending theArray.prototype
as described in the solution approach. This method would then be available on every array. -
We would define a
callback
function that takescurrentValue
(the name in this context),index
, andarray
as arguments. Our callback function would simply print the greeting to the console using the current name:function greeting(name, index) { console.log(`Hello, ${name}! You are at position ${index + 1}.`); }
-
We would then call our custom
forEach
method on our array of names, passing thegreeting
function as thecallback
.const names = ['Alice', 'Bob', 'Charlie']; names.forEach(greeting);
-
When we execute this code, our custom
forEach
method iterates over the array. For each element:a. It calls the
greeting
function usingcall
, which applies the givencontext
(if any). In this case, we haven't provided a context, so it defaults to the global context.b. This results in our
greeting
function being called with each name and its corresponding index. Thegreeting
function then logs the greeting to the console. -
As the loop progresses,
greeting
would be called with 'Alice' at index 0, 'Bob' at index 1, and 'Charlie' at index 2. -
The final output to the console would be:
Hello, Alice! You are at position 1. Hello, Bob! You are at position 2. Hello, Charlie! You are at position 3.
This small example illustrates how the custom forEach
method behaves similarly to the built-in forEach
, allowing us to execute a function for each element in an array without relying on the native method.
Solution Implementation
1class Array(list):
2 # The custom forEach function added to the Array class (inherits from list)
3 def forEach(self, callback, context=None):
4 # Iterate over each element in the list
5 for index, value in enumerate(self):
6 # If context is provided, apply it to the callback
7 if context:
8 callback(value, index, self, context)
9 else:
10 # Call the callback with the current element, its index, and the list itself
11 callback(value, index, self)
12
13# Example usage of the custom forEach function
14
15# Create an instance of Array with numbers
16arr = Array([1, 2, 3])
17
18# Define a callback function that doubles the value of each list element
19def double_values_callback(value, index, array, context=None):
20 # Update the list element to its doubled value
21 array[index] = value * 2
22
23# Define an optional context object (unused in this example)
24context = {"context": True}
25
26# Apply the custom forEach function to the arr Array using the doubleValuesCallback and context
27arr.forEach(double_values_callback, context)
28
29# Print the updated list to the console, which should show doubled values
30print(arr) # Output will be: [2, 4, 6]
31
1import java.util.function.BiConsumer;
2
3// Custom interface extending the functionality of BiConsumer interface
4interface ForEach<T> extends BiConsumer<T, Integer> {
5}
6
7/**
8 * A utility class to work with arrays
9 */
10class ArrayUtils {
11
12 /**
13 * A custom implementation of the forEach function that operates on arrays.
14 *
15 * @param array The array on which the operation is performed.
16 * @param callback The callback function to execute for each element.
17 * @param <T> The type of the elements in the array.
18 */
19 public static <T> void forEach(T[] array, ForEach<T> callback) {
20 // Iterate over each element in the array
21 for (int i = 0; i < array.length; i++) {
22 // Execute the callback function with the current element and its index
23 callback.accept(array[i], i);
24 }
25 }
26}
27
28/**
29 * Example usage of the custom forEach function.
30 */
31public class Main {
32 public static void main(String[] args) {
33 // Create an array of numbers
34 Integer[] arr = {1, 2, 3};
35
36 // Define a callback function that doubles the value of each array element
37 ForEach<Integer> doubleValuesCallback = new ForEach<>() {
38 public void accept(Integer value, Integer index) {
39 arr[index] = value * 2;
40 }
41 };
42
43 // Apply the custom forEach function to the arr array using the doubleValuesCallback
44 ArrayUtils.forEach(arr, doubleValuesCallback);
45
46 // Print the updated array to the console, which should show doubled values
47 for (Integer value : arr) {
48 System.out.println(value); // Output will be: 2, 4, 6
49 }
50 }
51}
52
1#include <iostream>
2#include <vector>
3#include <functional>
4
5// Declare a template for a custom forEach function
6template <typename T>
7void forEach(std::vector<T>& vec, std::function<void(T&, size_t, std::vector<T>&)> callback, void* context = nullptr) {
8 // Iterate over each element in the vector
9 for (size_t i = 0; i < vec.size(); ++i){
10 // Call the callback function, passing the current element by reference, its index, and the vector itself
11 callback(vec[i], i, vec);
12 }
13}
14
15int main() {
16 // Example usage of the custom forEach function
17
18 // Create a vector of numbers
19 std::vector<int> arr = {1, 2, 3};
20
21 // Define a callback function that doubles the value of each element of the vector
22 auto doubleValuesCallback = [](int& value, size_t index, std::vector<int>& array){
23 // Double the passed element's value
24 value *= 2;
25 };
26
27 // Define an optional context object (not utilized in this example)
28 // In this C++ version, it's not used but provided for compatibility with the original interface
29 void* context = nullptr;
30
31 // Apply the custom forEach function to the arr vector using the doubleValuesCallback
32 forEach(arr, doubleValuesCallback, context);
33
34 // Print the updated vector to the console, which should show doubled values
35 for (const int& value : arr) {
36 std::cout << value << " "; // Output will be: 2 4 6
37 }
38
39 return 0;
40}
41
1// Extending the Array prototype interface to include the custom forEach function
2interface Array<T> {
3 forEach(callback: (value: T, index: number, array: T[]) => void, context?: any): void;
4}
5
6// Custom implementation of the forEach function that adheres to TypeScript's syntax and type safety
7Array.prototype.forEach = function<T>(this: T[], callback: (value: T, index: number, array: T[]) => void, context?: any): void {
8 // Iterate over each element in the array
9 for (let i = 0; i < this.length; i++) {
10 // Call the callback function with the specified context, passing the current element, its index, and the array itself
11 callback.call(context, this[i], i, this);
12 }
13};
14
15// Example usage of the custom forEach function
16
17// Create an array of numbers
18const arr: number[] = [1, 2, 3];
19
20// Define a callback function that doubles the value of each array element
21const doubleValuesCallback = (value: number, index: number, array: number[]): void => {
22 array[index] = value * 2;
23};
24
25// Define an optional context object (not utilized in this example)
26const context = { "context": true };
27
28// Apply the custom forEach function to the arr array using the doubleValuesCallback and context
29arr.forEach(doubleValuesCallback, context);
30
31// Print the updated array to the console, which should show doubled values
32console.log(arr); // Output will be: [2, 4, 6]
33
Time and Space Complexity
The time complexity of the provided custom forEach
function is O(n)
, where n
is the number of elements in the array upon which forEach
is called. This is due to the for loop iterating through each element of the array exactly once.
The space complexity of forEach
is O(1)
(constant space complexity), assuming that the callback function's space complexity is also constant. The space used by the forEach
method itself does not grow with the size of the input array because it uses a fixed amount of additional space (a single loop counter i
).
Which type of traversal does breadth first search do?
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!