JavaScript Array entries() Method: Get Index-Value Pairs
Master the JavaScript Array entries() method to iterate over index-value pairs. Learn iterator patterns, destructuring, and practical use cases.
The entries()
method returns a new Array Iterator object that contains key-value pairs for each index in the array. Each entry is an array with two elements: the index and the value at that index.
Understanding Array entries()
The entries()
method provides a way to iterate over both indices and values simultaneously, returning them as [index, value]
pairs. This is particularly useful when you need both the position and the content of array elements.
Syntax
array.entries();
Parameters
The entries()
method takes no parameters.
Return Value
A new Array Iterator object that yields [index, value]
pairs.
Basic Usage
Simple Iteration
const fruits = ['apple', 'banana', 'cherry'];
// Get the iterator
const iterator = fruits.entries();
// Iterate manually using next()
console.log(iterator.next()); // { value: [0, 'apple'], done: false }
console.log(iterator.next()); // { value: [1, 'banana'], done: false }
console.log(iterator.next()); // { value: [2, 'cherry'], done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Using for...of with Destructuring
const colors = ['red', 'green', 'blue', 'yellow'];
// Iterate with destructuring
for (const [index, value] of colors.entries()) {
console.log(`${index}: ${value}`);
}
// Output:
// 0: red
// 1: green
// 2: blue
// 3: yellow
// Without destructuring
for (const entry of colors.entries()) {
console.log(`Index ${entry[0]} has value ${entry[1]}`);
}
Working with entries()
Converting to Array
const animals = ['cat', 'dog', 'bird', 'fish'];
// Convert iterator to array using spread
const entriesArray = [...animals.entries()];
console.log(entriesArray);
// [[0, 'cat'], [1, 'dog'], [2, 'bird'], [3, 'fish']]
// Using Array.from()
const entriesFrom = Array.from(animals.entries());
console.log(entriesFrom);
// [[0, 'cat'], [1, 'dog'], [2, 'bird'], [3, 'fish']]
// Convert to Map
const entriesMap = new Map(animals.entries());
console.log(entriesMap);
// Map(4) { 0 => 'cat', 1 => 'dog', 2 => 'bird', 3 => 'fish' }
Creating Objects from Entries
// Convert array to object with indices as keys
function arrayToObject(arr) {
const obj = {};
for (const [index, value] of arr.entries()) {
obj[index] = value;
}
return obj;
}
const items = ['first', 'second', 'third'];
console.log(arrayToObject(items));
// { '0': 'first', '1': 'second', '2': 'third' }
// Using reduce with entries
const objFromEntries = [...items.entries()].reduce((acc, [index, value]) => {
acc[`item_${index}`] = value;
return acc;
}, {});
console.log(objFromEntries);
// { item_0: 'first', item_1: 'second', item_2: 'third' }
Practical Examples
Array Transformation with Index
class ArrayTransformer {
static mapWithIndex(arr, callback) {
const result = [];
for (const [index, value] of arr.entries()) {
result.push(callback(value, index, arr));
}
return result;
}
static filterWithIndex(arr, predicate) {
const result = [];
for (const [index, value] of arr.entries()) {
if (predicate(value, index, arr)) {
result.push(value);
}
}
return result;
}
static groupByIndex(arr, groupSize) {
const groups = [];
let currentGroup = [];
for (const [index, value] of arr.entries()) {
currentGroup.push(value);
if ((index + 1) % groupSize === 0 || index === arr.length - 1) {
groups.push(currentGroup);
currentGroup = [];
}
}
return groups;
}
}
const numbers = [10, 20, 30, 40, 50];
// Map with index awareness
const indexed = ArrayTransformer.mapWithIndex(
numbers,
(val, idx) => `${idx}: ${val}`
);
console.log(indexed);
// ['0: 10', '1: 20', '2: 30', '3: 40', '4: 50']
// Filter based on index
const evenIndexed = ArrayTransformer.filterWithIndex(
numbers,
(val, idx) => idx % 2 === 0
);
console.log(evenIndexed); // [10, 30, 50]
// Group by index
console.log(ArrayTransformer.groupByIndex(numbers, 2));
// [[10, 20], [30, 40], [50]]
Finding Patterns with Indices
function findPatterns(arr) {
const patterns = {
duplicates: [],
increasing: [],
decreasing: [],
peaks: [],
valleys: [],
};
// Track duplicates with their indices
const valueMap = new Map();
for (const [index, value] of arr.entries()) {
// Check for duplicates
if (valueMap.has(value)) {
patterns.duplicates.push({
value,
indices: [valueMap.get(value), index],
});
} else {
valueMap.set(value, index);
}
// Check for patterns
if (index > 0) {
const prev = arr[index - 1];
if (value > prev) {
patterns.increasing.push({ index, value });
} else if (value < prev) {
patterns.decreasing.push({ index, value });
}
}
// Check for peaks and valleys
if (index > 0 && index < arr.length - 1) {
const prev = arr[index - 1];
const next = arr[index + 1];
if (value > prev && value > next) {
patterns.peaks.push({ index, value });
} else if (value < prev && value < next) {
patterns.valleys.push({ index, value });
}
}
}
return patterns;
}
const data = [1, 3, 2, 5, 3, 4, 2, 1];
console.log(findPatterns(data));
// {
// duplicates: [{ value: 3, indices: [1, 4] }, { value: 2, indices: [2, 6] }, { value: 1, indices: [0, 7] }],
// increasing: [{ index: 1, value: 3 }, { index: 3, value: 5 }, { index: 5, value: 4 }],
// decreasing: [{ index: 2, value: 2 }, { index: 4, value: 3 }, { index: 6, value: 2 }, { index: 7, value: 1 }],
// peaks: [{ index: 1, value: 3 }, { index: 3, value: 5 }],
// valleys: [{ index: 2, value: 2 }, { index: 6, value: 2 }]
// }
Parallel Array Processing
class ParallelArrayProcessor {
static *zipWithIndex(...arrays) {
const maxLength = Math.max(...arrays.map((arr) => arr.length));
for (let i = 0; i < maxLength; i++) {
const values = arrays.map((arr) => arr[i]);
yield [i, values];
}
}
static correlate(arr1, arr2) {
const result = [];
const entries1 = [...arr1.entries()];
const entries2 = [...arr2.entries()];
for (const [index1, value1] of entries1) {
for (const [index2, value2] of entries2) {
if (value1 === value2) {
result.push({
value: value1,
index1,
index2,
distance: Math.abs(index1 - index2),
});
}
}
}
return result;
}
static alignArrays(source, target, keyFn) {
const aligned = new Array(target.length).fill(null);
const targetMap = new Map();
// Build map of target values to indices
for (const [index, value] of target.entries()) {
const key = keyFn(value);
if (!targetMap.has(key)) {
targetMap.set(key, []);
}
targetMap.get(key).push(index);
}
// Align source values
for (const [sourceIndex, value] of source.entries()) {
const key = keyFn(value);
const targetIndices = targetMap.get(key);
if (targetIndices && targetIndices.length > 0) {
const targetIndex = targetIndices.shift();
aligned[targetIndex] = { sourceIndex, value };
}
}
return aligned;
}
}
// Example usage
const arr1 = ['a', 'b', 'c'];
const arr2 = [1, 2, 3, 4];
const arr3 = [true, false];
for (const [index, values] of ParallelArrayProcessor.zipWithIndex(
arr1,
arr2,
arr3
)) {
console.log(`Index ${index}: ${values}`);
}
// Index 0: a,1,true
// Index 1: b,2,false
// Index 2: c,3,
// Index 3: ,4,
// Find correlations
const data1 = [1, 2, 3, 2, 4];
const data2 = [3, 2, 1, 2, 3];
console.log(ParallelArrayProcessor.correlate(data1, data2));
// [
// { value: 1, index1: 0, index2: 2, distance: 2 },
// { value: 2, index1: 1, index2: 1, distance: 0 },
// { value: 2, index1: 1, index2: 3, distance: 2 },
// { value: 3, index1: 2, index2: 0, distance: 2 },
// { value: 3, index1: 2, index2: 4, distance: 2 },
// { value: 2, index1: 3, index2: 1, distance: 2 },
// { value: 2, index1: 3, index2: 3, distance: 0 }
// ]
Advanced Patterns
Custom Entry Iterators
class EnhancedArray extends Array {
*entriesFrom(startIndex = 0) {
for (let i = startIndex; i < this.length; i++) {
yield [i, this[i]];
}
}
*entriesReverse() {
for (let i = this.length - 1; i >= 0; i--) {
yield [i, this[i]];
}
}
*entriesWhere(predicate) {
for (const [index, value] of this.entries()) {
if (predicate(value, index)) {
yield [index, value];
}
}
}
*entriesStep(step = 1) {
for (let i = 0; i < this.length; i += step) {
yield [i, this[i]];
}
}
}
const enhanced = new EnhancedArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Start from index 5
console.log([...enhanced.entriesFrom(5)]);
// [[5, 6], [6, 7], [7, 8], [8, 9], [9, 10]]
// Reverse entries
console.log([...enhanced.entriesReverse()]);
// [[9, 10], [8, 9], [7, 8], ..., [0, 1]]
// Conditional entries
console.log([...enhanced.entriesWhere((v) => v % 2 === 0)]);
// [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
// Step entries
console.log([...enhanced.entriesStep(3)]);
// [[0, 1], [3, 4], [6, 7], [9, 10]]
State Tracking with Entries
class StateTracker {
constructor(initialArray) {
this.states = [initialArray];
this.currentIndex = 0;
}
update(index, value) {
const newState = [...this.states[this.currentIndex]];
newState[index] = value;
this.states.push(newState);
this.currentIndex++;
return this;
}
*changeLog() {
for (let i = 1; i < this.states.length; i++) {
const prev = this.states[i - 1];
const curr = this.states[i];
for (const [index, value] of curr.entries()) {
if (prev[index] !== value) {
yield {
stateIndex: i,
arrayIndex: index,
oldValue: prev[index],
newValue: value,
};
}
}
}
}
getDiff(stateIndex1, stateIndex2) {
const state1 = this.states[stateIndex1];
const state2 = this.states[stateIndex2];
const diffs = [];
for (const [index, value] of state2.entries()) {
if (state1[index] !== value) {
diffs.push({
index,
from: state1[index],
to: value,
});
}
}
return diffs;
}
}
const tracker = new StateTracker([1, 2, 3, 4, 5]);
tracker.update(0, 10).update(2, 30).update(4, 50);
console.log([...tracker.changeLog()]);
// [
// { stateIndex: 1, arrayIndex: 0, oldValue: 1, newValue: 10 },
// { stateIndex: 2, arrayIndex: 2, oldValue: 3, newValue: 30 },
// { stateIndex: 3, arrayIndex: 4, oldValue: 5, newValue: 50 }
// ]
Matrix Operations with Entries
class Matrix {
constructor(rows, cols, initialValue = 0) {
this.rows = rows;
this.cols = cols;
this.data = Array(rows)
.fill(null)
.map(() => Array(cols).fill(initialValue));
}
*entries() {
for (const [rowIndex, row] of this.data.entries()) {
for (const [colIndex, value] of row.entries()) {
yield [[rowIndex, colIndex], value];
}
}
}
*entriesByRow() {
for (const [rowIndex, row] of this.data.entries()) {
yield [rowIndex, row.entries()];
}
}
*entriesByColumn() {
for (let col = 0; col < this.cols; col++) {
const columnEntries = function* (matrix, colIndex) {
for (let row = 0; row < matrix.rows; row++) {
yield [row, matrix.data[row][colIndex]];
}
};
yield [col, columnEntries(this, col)];
}
}
forEach(callback) {
for (const [[row, col], value] of this.entries()) {
callback(value, row, col, this);
}
}
}
const matrix = new Matrix(3, 3);
matrix.data = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
// All entries
console.log([...matrix.entries()]);
// [[[0,0], 1], [[0,1], 2], [[0,2], 3], [[1,0], 4], ...]
// Process each element
matrix.forEach((value, row, col) => {
console.log(`[${row},${col}] = ${value}`);
});
Working with Sparse Arrays
// entries() includes all indices, even empty slots
const sparse = [1, , , 4, , 6];
console.log([...sparse.entries()]);
// [[0, 1], [1, undefined], [2, undefined], [3, 4], [4, undefined], [5, 6]]
// Function to get only defined entries
function* definedEntries(arr) {
for (let i = 0; i < arr.length; i++) {
if (i in arr) {
yield [i, arr[i]];
}
}
}
console.log([...definedEntries(sparse)]);
// [[0, 1], [3, 4], [5, 6]]
// Compact sparse array preserving indices
function compactSparse(arr) {
const result = [];
for (const [index, value] of definedEntries(arr)) {
result.push({ index, value });
}
return result;
}
console.log(compactSparse(sparse));
// [{ index: 0, value: 1 }, { index: 3, value: 4 }, { index: 5, value: 6 }]
Performance Considerations
// Performance comparison for different iteration methods
const largeArray = Array.from({ length: 100000 }, (_, i) => i);
// Using entries()
console.time('entries');
for (const [index, value] of largeArray.entries()) {
// Process
}
console.timeEnd('entries');
// Using traditional for loop
console.time('for loop');
for (let i = 0; i < largeArray.length; i++) {
const index = i;
const value = largeArray[i];
// Process
}
console.timeEnd('for loop');
// Using forEach
console.time('forEach');
largeArray.forEach((value, index) => {
// Process
});
console.timeEnd('forEach');
// Traditional for loops are typically fastest for simple operations
Best Practices
- Use Destructuring: Always destructure
[index, value]
for clarity - Consider Performance: Use traditional loops for performance-critical code
- Handle Sparse Arrays: Be aware that entries() includes empty slots
- Combine with Map/Set: Convert to Map when you need key-value operations
- Memory Efficiency: Iterators don't create intermediate arrays
Conclusion
The entries()
method is a powerful tool for working with both array indices and values simultaneously. It provides a clean, iterator-based approach that integrates well with modern JavaScript features like destructuring and for...of loops. Whether you're tracking positions, correlating data, or building complex transformations, entries()
offers an elegant solution for index-aware array operations.