enumerable objects
indexable objects
JavaScript
programming concepts
data structures

Object is enumerable but not indexable?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Being enumerable and being indexable are different capabilities, even though they are often confused in everyday coding. Enumerable data can be iterated in sequence, while indexable data supports random access by position. Knowing this distinction helps you avoid conversion overhead, one-shot iterator bugs, and incorrect API contracts.

Core Difference in Access Semantics

Enumerable means values can be consumed one after another. Indexable means you can request a specific position directly, such as the fifth element.

Common enumerable but not indexable sources:

  • JavaScript generators
  • JavaScript sets
  • stream readers
  • Python iterators and generators

These sources are excellent for streaming pipelines but cannot guarantee direct position access.

JavaScript Generator Example

javascript
1function* values() {
2  yield "a";
3  yield "b";
4  yield "c";
5}
6
7const g = values();
8for (const item of g) {
9  console.log(item);
10}
11
12// direct index access does not work
13console.log(g[0]);

The generator is iterable, but not array-like.

Set Example and Controlled Conversion

A Set is iterable and preserves insertion order, yet bracket indexing still does not apply.

javascript
1const set = new Set(["red", "green", "blue"]);
2
3for (const color of set) {
4  console.log(color);
5}
6
7console.log(set[1]); // undefined

If you truly need positional access, convert intentionally:

javascript
const arr = Array.from(set);
console.log(arr[1]);

Do this only when index operations justify the memory cost.

Streaming-Friendly Access Without Full Materialization

Sometimes you only need one element from an iterable. Full conversion to array may be wasteful.

javascript
1function takeFirstN(iterable, n) {
2  const out = [];
3  for (const item of iterable) {
4    out.push(item);
5    if (out.length === n) break;
6  }
7  return out;
8}
9
10const firstTwo = takeFirstN(new Set([10, 20, 30, 40]), 2);
11console.log(firstTwo);

This pattern keeps memory bounded and supports large or infinite iterables.

Python Parallel for the Same Concept

python
1def stream_numbers():
2    for i in range(10):
3        yield i * 3
4
5g = stream_numbers()
6for v in g:
7    print(v)
8
9# g[0] would fail because generator is not indexable

Need a specific position without full list conversion:

python
1import itertools
2
3third = next(itertools.islice(stream_numbers(), 2, None))
4print(third)

This preserves streaming behavior and avoids unnecessary memory growth.

API Design Guidance

When designing function signatures, be explicit:

  • accept iterables when sequential scanning is enough
  • require arrays or lists only when random access is required

JavaScript example:

javascript
1function sumIterable(items) {
2  let total = 0;
3  for (const item of items) total += item;
4  return total;
5}
6
7function pairByIndex(arrayLike) {
8  return [arrayLike[0], arrayLike[1]];
9}

These two functions have different requirements and should not be treated as interchangeable.

One-Shot Iterable Hazards

Some iterables are consumable only once. If a helper function iterates through the entire source for logging or metrics, the next consumer may receive nothing.

Use clear ownership rules:

  • either consume once and document it
  • or cache materialized results when multiple passes are required

Unexpected exhaustion is a common production bug in streaming pipelines. When performance tuning, profile allocation and iteration counts before converting iterable sources to arrays, because silent materialization can dominate both memory and latency. A small utility that records whether inputs are arrays, sets, or generators can prevent accidental indexing assumptions from spreading through shared helper libraries.

Common Pitfalls

  • Assuming every iterable supports bracket indexing.
  • Converting large streams to arrays for trivial access patterns.
  • Forgetting that some iterables are one-shot and cannot be reused.
  • Designing APIs with unclear expectations about access semantics.
  • Mixing random-access and streaming assumptions in the same algorithm.

Summary

  • Enumerable and indexable represent different data access capabilities.
  • Generators and sets are iterable but not directly indexable.
  • Convert to indexed collections only when random access is necessary.
  • Prefer bounded streaming helpers for large or infinite inputs.
  • Make API requirements explicit to prevent hidden performance and correctness issues.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.