Python
Lists
Indexing
Data Structures
Programming Tips

Access multiple elements of list knowing their index

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

To access multiple elements from a Python list by their indices, use a list comprehension ([lst[i] for i in indices]), operator.itemgetter, or NumPy array indexing. Python does not support multi-index subscripting on regular lists (like lst[1, 3, 5]), so you need one of these approaches. For performance-critical code with large arrays, NumPy's fancy indexing is the fastest option.

List Comprehension (Most Common)

python
1my_list = ["a", "b", "c", "d", "e", "f"]
2indices = [0, 2, 4]
3
4# Access elements at indices 0, 2, and 4
5result = [my_list[i] for i in indices]
6print(result)  # ['a', 'c', 'e']
7
8# Works with any iterable of indices
9result = [my_list[i] for i in (1, 3, 5)]
10print(result)  # ['b', 'd', 'f']
11
12# With negative indices
13result = [my_list[i] for i in [-1, -2, 0]]
14print(result)  # ['f', 'e', 'a']

operator.itemgetter

python
1from operator import itemgetter
2
3my_list = ["a", "b", "c", "d", "e", "f"]
4
5# Single call extracts multiple elements
6getter = itemgetter(0, 2, 4)
7result = getter(my_list)
8print(result)  # ('a', 'c', 'e') — returns a tuple
9
10# Or in one line
11result = itemgetter(0, 2, 4)(my_list)
12
13# Convert to list if needed
14result = list(itemgetter(0, 2, 4)(my_list))
15print(result)  # ['a', 'c', 'e']
16
17# Unpack directly
18first, third, fifth = itemgetter(0, 2, 4)(my_list)
19
20# Use with sorted() or map()
21data = [("Alice", 90), ("Bob", 85), ("Charlie", 95)]
22sorted_by_score = sorted(data, key=itemgetter(1))
23print(sorted_by_score)  # [('Bob', 85), ('Alice', 90), ('Charlie', 95)]

itemgetter is slightly faster than list comprehension for small numbers of indices because it avoids the overhead of a Python loop.

NumPy Fancy Indexing

python
1import numpy as np
2
3arr = np.array(["a", "b", "c", "d", "e", "f"])
4indices = [0, 2, 4]
5
6# Fancy indexing — pass a list of indices directly
7result = arr[indices]
8print(result)  # ['a' 'c' 'e']
9
10# Works with numpy integer arrays too
11idx = np.array([1, 3, 5])
12result = arr[idx]
13print(result)  # ['b' 'd' 'f']
14
15# Boolean mask indexing
16mask = [True, False, True, False, True, False]
17result = arr[mask]
18print(result)  # ['a' 'c' 'e']
19
20# 2D array — select specific rows
21matrix = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
22rows = [0, 2, 3]
23result = matrix[rows]
24print(result)
25# [[1 2]
26#  [5 6]
27#  [7 8]]

map() with list.getitem

python
1my_list = ["a", "b", "c", "d", "e", "f"]
2indices = [0, 2, 4]
3
4result = list(map(my_list.__getitem__, indices))
5print(result)  # ['a', 'c', 'e']

This works but using dunder methods directly is generally discouraged. List comprehension is more readable.

Slice for Contiguous Indices

When indices are contiguous, use slicing instead:

python
1my_list = ["a", "b", "c", "d", "e", "f"]
2
3# Contiguous range — use slice
4result = my_list[1:4]
5print(result)  # ['b', 'c', 'd']
6
7# Every other element
8result = my_list[::2]
9print(result)  # ['a', 'c', 'e']
10
11# Reverse
12result = my_list[::-1]
13print(result)  # ['f', 'e', 'd', 'c', 'b', 'a']

Slicing is O(k) where k is the slice length, and it returns a new list (a shallow copy).

Handling Out-of-Range Indices

python
1my_list = ["a", "b", "c"]
2indices = [0, 1, 5, 2]
3
4# List comprehension raises IndexError for invalid indices
5# result = [my_list[i] for i in indices]  # IndexError: list index out of range
6
7# Safe version — skip invalid indices
8result = [my_list[i] for i in indices if 0 <= i < len(my_list)]
9print(result)  # ['a', 'b', 'c']
10
11# Safe version — return default for invalid indices
12result = [my_list[i] if 0 <= i < len(my_list) else None for i in indices]
13print(result)  # ['a', 'b', None, 'c']

Performance Comparison

python
1import timeit
2from operator import itemgetter
3import numpy as np
4
5my_list = list(range(10000))
6indices = list(range(0, 10000, 3))  # ~3333 indices
7
8# List comprehension
9timeit.timeit(lambda: [my_list[i] for i in indices], number=1000)
10# ~0.25 seconds
11
12# operator.itemgetter (for small index counts)
13getter = itemgetter(*indices)
14timeit.timeit(lambda: getter(my_list), number=1000)
15# ~0.18 seconds
16
17# NumPy (fastest for large arrays)
18arr = np.array(my_list)
19idx = np.array(indices)
20timeit.timeit(lambda: arr[idx], number=1000)
21# ~0.02 seconds
MethodSpeedReturnsBest For
List comprehensionMediumlistGeneral use, readable
itemgetterFasttupleSmall index sets, sorting keys
NumPy indexingFastestndarrayLarge arrays, numerical data
map(__getitem__)MediumlistFunctional style
SlicingFastestlistContiguous ranges only

Common Pitfalls

  • Using a for loop instead of list comprehension: Writing result = []; for i in indices: result.append(lst[i]) works but is slower and more verbose. List comprehension [lst[i] for i in indices] is the Pythonic, faster alternative.
  • Assuming itemgetter returns a list: itemgetter(0, 2)(lst) returns a tuple, not a list. If you need a list, wrap it in list(). Also, itemgetter(0)(lst) with a single index returns the element itself, not a tuple.
  • Modifying the original list through indexed access: [lst[i] for i in indices] creates a shallow copy. If the elements are mutable objects (like nested lists), modifying them through the new list also modifies the original. Use copy.deepcopy() if independence is needed.
  • Using NumPy for small lists: Converting a small Python list to a NumPy array just for indexing adds overhead that exceeds the benefit. NumPy fancy indexing is only faster for arrays with thousands of elements or more.
  • Not validating indices before accessing: Accessing lst[i] with an out-of-range index raises IndexError. When indices come from user input or external data, validate them with if 0 <= i < len(lst) before accessing, or use try/except for cleaner error handling.

Summary

  • Use list comprehension [lst[i] for i in indices] for the most readable, general-purpose approach
  • Use operator.itemgetter(*indices) for concise extraction and as a sorting key function
  • Use NumPy fancy indexing arr[indices] for maximum performance on large numerical arrays
  • Use slicing (lst[start:stop:step]) when indices form a contiguous or regularly spaced range
  • Validate indices before accessing to avoid IndexError on out-of-range values
  • List comprehension and itemgetter return shallow copies — be aware of mutable element references

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

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

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design