For Each Loops in 5 Languages

In this series, we look at common practices and paradigms in 5 popular programming and scripting languages (JavaScript, Node.js, C++, Java, and PHP). We've separated JavaScript and Node.js to cover both ES5 (browser-safe) and ES6 (node-safe) features. For some entries in the series, a given language may not support a topic--in which case we'll attempt to find the closest analogue. This series is aimed at those with existing programming experience who are expected to have an existing, basic understanding of the topics covered, and will not server as an "in-depth" guide, but will, instead, provide a state overview for each language, and provide links to additional resources for more information.

In this post we'll be looking at the constructs in our 5 languages which allow for iteration over items in an array (or collection), with each iteration providing access to a single element through a named variable--something which is commonly called a for each loop (and sometimes an enhanced for loop, or a range loop). For languages which blur the boundaries between arrays and objects, we'll be concentrating on that language's array and array-like constructs, and will not be covering object property iteration. A number of the for each patterns shown below make use of anonymous functions--you can learn more about these in Anonymous Functions and Lambda Expressions in 5 Languages.

Jump to:

JavaScript (including Node.js)

Arrays in JavaScript are a specialised object implementation, and as such have methods. An array object's forEach() method can be used to execute a callback for each element in an array, in ascending order. The callback function will be passed three arguments for each iteration: the iteration element, the index of the iteration element, and a reference to the array being iterated over. When used with sparse arrays, the forEach() method will skip uninitialised or deleted entries.

var numbers = [1, 2, 3, 4, 5];

/**
 * output:
 * value 1 is at index 0
 * value 2 is at index 1
 * value 3 is at index 2
 * value 4 is at index 3
 * value 5 is at index 4
 */
numbers.forEach(function(number, index, array) {
  console.log('value ' +  number + ' is at index ' + index);
});

forEach() loop control:

ActionAvailable
breakNot available.
continueNot available, but you can prematurely return from the callback to achieve the same effect.

Result of modifying an Array during forEach() iteration:

ActionOutcome
Add an elementPossible, but the callback will not be executed for the new element.
Remove an elementIf the element has not yet been encountered, it will be safely skipped. If the element has already been encountered, the next element in line will be skipped (think of what happens when you remove an element in a standard for loop, but do not modify i to compensate).
Modify an element valueIf you modify an upcoming element, the new value will be passed to the callback when the element is iterated over.

If you need a similar construct that's iteration can be broken, you can make use of an array's some() method instead. The some() method is used to test that at least 1 element in an array passes a specified test function. It features the same callback signature as the forEach() method, but the callback should return a boolean value which determines if iteration should continue or not.

Given that the method's purpose is to pass array elements through a test function, to determine if any item meets the test criteria, a callback which returns a value of false (or a false-like value) will result in iteration continuing to the next element (the element does not match the test criteria, check additional elements). A return value of true will cease iteration (the element matches the test criteria, there's no need to check additional elements).

The some() method is not designed as a breakable forEach() alternative, so using it as such could be considered a little bit of a hack, but it will work:

var numbers = [1, 2, 3, 4, 5];

/**
 * output:
 * value 1 is at index 0
 * value 2 is at index 1
 */
numbers.some(function(number, index, array) {
  console.log('value ' + number + ' is at index ' + index);
  return number === 2; // break after value 2 is encountered
});

It's worth noting that these methods only exist on true array objects (Array objects, typed arrays) and are not available on array-like objects (a function's arguments array, a DOM element list, etc.)

The are no interface differences for these methods between ES5 and ES6, which is why we have bundled both JavaScript and Node.js into one section. However, you should keep in mind that in Node.js you are safe to use other ES6 features, such as arrow functions for defining callbacks:

let numbers = [1, 2, 3, 4, 5];

numbers.forEach((number, index, array) => {
  console.log(`value ${number} is at index ${index}`);
});

More information:

C++

The C++11 standard introduced range-based for loops to the language as an alternative to the standard library's for_each algorithm (explained below). To declare a range-based for loop, use the for keyword followed by parenthesis, and a loop body. Between the parenthesis, you declare a variable (type and name) which will hold each individual value as it is iterated over, and you follow this with a colon and the name of an array or collection you want to iterate over.

The following is an example of a range-based for loop used with a primitive array:

int numbers[] = {1, 2, 3, 4, 5};

// Output: 
// 1
// 2
// 3
// 4
// 5
// Read as: for each int as number in numbers
for(const int& number: numbers) {
  std::cout << number << std::endl;
}

The following is an example of a range-based for loop used with a collection (a vector):

auto number_list = std::vector<int>({ 1, 2, 3, 4, 5 });

for(const auto& number: number_list) {
  std::cout << number << std::endl;
}

Range-based for loop control:

ActionAvailable
breakAvailable.
continueAvailable.

Result of modifying a collection during range-based for loop iteration:

ActionOutcome
Add an elementDon't do it. Bad things will happen (the exact outcome will vary based on the collection type, but you should expect invalidated iterators, exceptions, etc.)
Remove an elementSeriously, really bad things will happen!
Modify an element valueIf you modify an upcoming element, the new value will be assigned to the named variable when it is iterated over.

Prior to C++11, the standard library for_each algorithm was used for range-based iteration. It is still possible to use this algorithm, and it can also be mixed with C++11 features (such as lambda expressions) for an alternative syntax. To use this algorithm, you must pass a start and end iterator, and a pointer to a function which will be called for each element in the specified range. In the example below, we use the standard library begin() and end() functions to construct iterators for a primitive array, and a lambda expression is used in place of an explicit function pointer:

int numbers[] = {1, 2, 3, 4, 5};

std::for_each(std::begin(numbers), std::end(numbers), [](const auto& number){
  std::cout << number << std::endl;
});

Range-based for loop control:

ActionAvailable
breakNot available.
continueNot available, but you can prematurely return from the lambda expression or pointed function to achieve the same effect.

Result of modifying a collection during range-based for loop iteration:

ActionOutcome
Add an elementSeriously, just don't modify something you're iterating over in C++.
Remove an elementSeriously!
Modify an element valueIf you modify an upcoming element, the new value will be assigned to the named variable when it is iterated over.

More information:

Java

Java SE5 introduced the enhanced for loop as a syntactically concise way of iterating over all of the elements in an array or a collection. To declare an enhanced for loop, you use the for keyword followed by parenthesis, and a loop body. Between the parenthesis, you declare a variable (type and name) which will hold each individual value as it is iterated over, and you follow this with a colon and the name of an array or collection you want to iterate over.

The following is an example of an enhanced for loop used with a primitive array:

int[] numbers = {1, 2, 3, 4, 5};

// Output: 
// 1
// 2
// 3
// 4
// 5
// Read as: for each int as number in numbers
for(int number: numbers) {
  System.out.println(number);
}

The following is an example of an enhanced for loop used with a collection (an Array List):

ArrayList<Integer> numberList = new ArrayList<>();
numberList.add(1);
numberList.add(2);
numberList.add(3);
numberList.add(4);
numberList.add(5);

for(int number: numberList) {
  System.out.println(number);
}

Enhanced for loop control:

ActionAvailable
breakAvailable.
continueAvailable.

Result of modifying a collection during enhanced for loop iteration:

ActionOutcome
Add an elementA ConcurrentModificationException will be thrown.
Remove an elementA ConcurrentModificationException will be thrown
Modify an element valueIf you modify an upcoming element, the new value will be assigned to the named variable when it is iterated over.

Since Java SE8, all objects which implement the Iterable interface (including all collection types) provide a forEach() method which can be used to execute an action for each iterable element, performed in the class's iteration order. For each iteration, the action will be passed the iteration element:

ArrayList<Integer> numberList = new ArrayList<>();
numberList.add(1);
numberList.add(2);
numberList.add(3);
numberList.add(4);
numberList.add(5);

numberList.forEach(number -> {
  System.out.println(number);
});

forEach() loop control:

ActionAvailable
breakNot available.
continueNot available, but you can prematurely return from an action (a lambda function) to achieve the same effect.

Result of modifying a collection during forEach() iteration:

ActionOutcome
Add an elementA ConcurrentModificationException will be thrown.
Remove an elementA ConcurrentModificationException will be thrown
Modify an element valueIf you modify an upcoming element, the new value will be assigned to the named variable when it is iterated over.

More information:

PHP

PHP 4 introduced the foreach() construct as a syntactically concise way of iterating over both indexed, and custom keyed arrays. To use the foreach() construct you provide an argument which is composed of the name of the array you want to iterate over, followed by the as keyword, and then the name you wish to assign to elements as they are encountered. In the following example, the foreach() construct is used to iterate over an array of 5 numbers ($numbers). In each iteration, the value being passed over is available through the $number variable

$numbers = array(1, 2, 3, 4, 5);

/**
 * Output: 
 * 1
 * 2
 * 3
 * 4
 * 5
 */
foreach($numbers as $number) {
  echo $number, "\n"; 
}

By default, $number will be assigned by value. To change this behaviour and assign by reference, you can prepend an ampersand (&) to the named variable:

$numbers = array(1, 2, 3, 4, 5);

/**
 * Notice '&' before '$number'
 */
foreach($numbers as &$number) {
  echo $number, "\n"; 
}

If you need to access array indexes (or custom keys, if used) you can use the following alternative syntax:

// Indexed array. Output:
// 0: 1
// 1: 2
// 2: 3
$numbers = array(1, 2, 3);

foreach($numbers as $key => &$number) {
  echo $key, ': ', $number, "\n"; 
}

// Keyed array. Output: 
// first: 1
// second: 2
// third: 3
$keyed_numbers = array('first' => 1, 'second' => 2, 'third' => 3);

foreach($keyed_numbers as $key => &$number) {
  echo $key, ': ', $number, "\n"; 
}

foreach() loop control:

ActionAvailable
breakAvailable.
continueAvailable.

Result of modifying an array during foreach() iteration (variable assigned by reference--as &$name):

ActionOutcome
Add an elementPossible, but not always safe. If the position of the new element has not yet been encountered at the time of insertion, it will be iterated over. If the position of the new element has already been encountered, one or more upcoming elements may be skipped.
Remove an elementPossible. If the position of the removed element has not yet been encountered at the time of removal, it will be safely skipped. If the position of the removed element has already been encountered, the remainder of the array will be iterated over as if the element had not been removed.
Modify an element valueIf you modify an upcoming element, the new value will be passed to the callback when the element is iterated over.

Result of modifying an array during foreach() iteration (variable assigned by value--as $name):

ActionOutcome
Add an elementNo changes to the array or its values are reflected during iteration.
Remove an elementNo changes to the array or its values are reflected during iteration.
Modify an element valueNo changes to the array or its values are reflected during iteration.

More information: