Arrays in Python

By the Syncfusion DevTutorials team · Last updated

The array module: type codes, indexing from both ends, inserting and removing, searching, every array method, enumerate() and the numeric built-ins.

Think about an egg tray.

It holds twelve eggs. Every slot is the same size and the same shape, because every slot holds the same kind of thing. You find the fourth egg by counting along, not by searching.

That is an array: many values of one kind, kept in order, each reachable by its position.

What You Will Learn

In this lesson, you will learn:

  • What an array is, and what Python uses instead most of the time
  • How to create one, and what the type code means
  • How to reach any element, counting from the front or the back
  • How to change, add and remove elements
  • How to search an array
  • The methods an array carries with it
  • How enumerate() gives you the position and the value together
  • The numeric built-ins you will use on arrays every day

By the end of this lesson, you will be able to build arrays, reach and change any element by position, add and remove values, and use the built-in functions to work out totals, averages, highest and lowest values.

Even though Python programmers usually use lists, understanding arrays helps you learn the core ideas behind indexed collections.

Arrays

Introduction to Arrays

An array is a collection of values of the same type, stored one after another in memory, each identified by a number called its index.

Because every element is the same size, the computer can jump straight to any position without looking at the ones before it. That is why marks[500] is just as fast as marks[0].

Here is that idea in Python. Three marks are held under one name, and marks[0] is the first one, because positions start at 0:

Three marks in one name

from array import array

marks = array("i", [78, 85, 60])

print(marks)
print(marks[0])
print(len(marks))

An array holds many values of the same kind, in order, each reachable by its position.

The entire collection is stored in one variable, and each value can be reached by its position.

Arrays in Python

Here is the part that confuses people coming from other languages.

In Java or C you reach for an array constantly. In Python you almost always use a list instead.

A list does the same job, with no import

marks = [78, 85, 60]

print(marks)
print(marks[0])
print(len(marks))

A list is built in, takes any mix of types, and has more methods. It is what Python programmers use for a collection of marks.

The array module exists for one reason: storing a lot of numbers compactly. An array of a million whole numbers uses far less memory than a list of a million whole numbers, because it stores the raw numbers rather than full Python objects.

The same values, two different costs

import sys
from array import array

list_marks = [78, 85, 60, 92, 45]
array_marks = array("i", [78, 85, 60, 92, 45])

print("List holds:", list_marks)
print("Array holds:", array_marks)
print("Bytes per number in the array:", array_marks.itemsize)
print("Whole array, in bytes:", array_marks.buffer_info()[1] * array_marks.itemsize)
print("List object alone, in bytes:", sys.getsizeof(list_marks))

The array stores five numbers in 20 bytes. The list needs that much just for its own structure, before counting the five number objects it points at.

So: use a list unless you are holding a great many numbers and memory matters. Learn arrays anyway, because the ideas — index, traverse, insert, delete, search — are the same ones every collection uses.

Array Characteristics

An array has a small set of rules, and every one of them shapes how you use it:

CharacteristicWhat it means
Same typeevery element must match the type code
Orderedelements keep the order you put them in
Indexedthe first element is at 0
Changeableyou can replace, add and remove elements
Compactthe raw numbers are stored, not Python objects

The "same type" rule is the real difference from a list, and it is enforced:

An array refuses the wrong type

from array import array

marks = array("i", [78, 85])
marks.append(7.5)

TypeError — i means whole numbers, and 7.5 is not one. A list would have accepted it without a word.

Creating Arrays

Importing the array Module

Arrays are not built in. The array module ships with Python, so there is nothing to install.

Two ways to import it

import array

a = array.array("i", [78, 85])
print(a)

from array import array

b = array("i", [60, 92])
print(b)

The second form is what you will usually see, because array.array(...) reads oddly.

Creating Arrays with array()

Making an array is a single call:

array(typecode, values)

The type code is a single letter saying what kind of value the array holds. It is not optional.

The two things an array needs

from array import array

marks = array("i", [78, 85, 60])

print(marks)
print("Type code:", marks.typecode)
print("Bytes each:", marks.itemsize)

An array can start empty and be filled later:

Starting empty

from array import array

marks = array("i")

print("Empty:", marks, len(marks))

marks.append(78)
marks.append(85)

print("Filled:", marks, len(marks))

Integer Arrays

i holds whole numbers, taking 4 bytes each.

Whole numbers

from array import array

marks = array("i", [78, 85, 60, 92])

print(marks)
print("Total:", sum(marks))
print("Highest:", max(marks))

Float Arrays

d holds decimal numbers, taking 8 bytes each. f is the smaller, less precise version.

Decimal numbers

from array import array

averages = array("d", [78.5, 85.25, 60.75])

print(averages)
print("Average of averages:", round(sum(averages) / len(averages), 2))
print("Bytes each:", averages.itemsize)

Putting a whole number into a d array is fine — it is widened, exactly as 7 + 2.5 is:

A whole number in a decimal array

from array import array

averages = array("d", [78.5])
averages.append(85)

print(averages)

Character Arrays

The array module has a type code u for single characters.

An array of characters

from array import array

name = array("u", "Asha")

print(name)
print(name[0])
print(name.tounicode())

Be careful with this one. The u type code is deprecated, which means it still works today but is on its way out of Python. For text, use a plain string, and for a collection of words use a list of strings.

What to use for text instead

name = "Asha"
subjects = ["Maths", "Science", "English"]

print(name[0])
print(subjects[0])
print(len(name), len(subjects))

Strings and lists support the same indexing you are learning here, so nothing is lost.

Array Type Codes

The codes are one letter each, and each letter fixes the size of one element:

CodeHoldsBytesExample
bsmall whole number, signed1array("b", [-5, 5])
Bsmall whole number, no minus1array("B", [0, 255])
iwhole number2 or morearray("i", [78])
Iwhole number, no minus2 or morearray("I", [78])
lbigger whole number4 or morearray("l", [100000])
qvery big whole number8array("q", [10 ** 15])
fdecimal, less precise4array("f", [78.5])
ddecimal8array("d", [78.5])
uone character (deprecated)2 or 4array("u", "Asha")

Different codes, different sizes

from array import array

for code in ["b", "i", "l", "q", "f", "d"]:
    sample = array(code, [1])
    print(code, "->", sample.itemsize, "bytes each")

Choose the smallest code that fits your numbers. A code too small will refuse the value rather than wrap around quietly:

A number too big for its code

from array import array

small = array("b", [127])
small.append(200)

OverflowError — b holds up to 127, and 200 does not fit.

Once an array has been created, the next step is learning how to read values from it.

Accessing Array Elements

Array Indexing

An index is the position of an element. Python counts from 0, so the first element is at index 0.

Positive Indexing

Counting from the front

from array import array

marks = array("i", [78, 85, 60, 92])

print("First:", marks[0])
print("Second:", marks[1])
print("Last:", marks[3])

With four elements, the valid indexes are 0, 1, 2 and 3. The last index is always one less than the length, which is the single most common off-by-one in programming.

One step past the end

from array import array

marks = array("i", [78, 85, 60, 92])

print(marks[4])

IndexError: array index out of range.

Negative Indexing

A negative index counts from the back. -1 is the last element.

Counting from the back

from array import array

marks = array("i", [78, 85, 60, 92])

print("Last:", marks[-1])
print("Second from last:", marks[-2])
print("First:", marks[-len(marks)])

marks[-1] is much safer than marks[len(marks) - 1], and says the same thing.

Slicing works too, taking a range of positions:

Taking a slice

from array import array

marks = array("i", [78, 85, 60, 92, 45])

print(marks[1:3])
print(marks[:2])
print(marks[2:])
print(marks[::-1])

A slice goes up to but not including the second number, exactly like range().

Traversing Arrays

Traversing means visiting every element in turn.

Visiting every element

from array import array

marks = array("i", [78, 85, 60])

for mark in marks:
    print("Mark:", mark)

That is the form to reach for. Looping over the indexes is possible, but only worth it when you actually need the position:

Looping over the positions instead

from array import array

marks = array("i", [78, 85, 60])

for position in range(len(marks)):
    print(position, "->", marks[position])

Reading values is only half the story. Arrays are mutable, which means you can change their contents after creation.

Modifying Arrays

Updating Array Elements

Assign to a position to replace what is there.

Replacing one element

from array import array

marks = array("i", [78, 85, 60])

print("Before:", marks)

marks[2] = 75

print("After:", marks)

The array did not grow. One value was swapped for another.

Inserting Elements

insert(position, value) puts a value before the given position, and everything after it shifts along.

Inserting in the middle

from array import array

marks = array("i", [78, 85, 60])

marks.insert(1, 100)

print(marks)

100 is now at index 1, and 85 and 60 have each moved one place right.

Inserting at the front

from array import array

marks = array("i", [78, 85])

marks.insert(0, 50)

print(marks)

Inserting at the front is the slowest thing you can do to an array, because every other element has to move. Adding at the end moves nothing.

Appending Elements

append(value) adds one value to the end.

Adding to the end

from array import array

marks = array("i", [78, 85])

marks.append(60)
marks.append(92)

print(marks)
print("Length now:", len(marks))

Removing Array Elements

Using remove()

remove(value) deletes the first element equal to that value. It works by value, not by position.

Removing by value

from array import array

marks = array("i", [78, 85, 60, 85])

marks.remove(85)

print(marks)

Only the first 85 went. The second is still there.

If the value is not present, Python stops:

Removing something that is not there

from array import array

marks = array("i", [78, 85])

marks.remove(99)

ValueError — check with in first when you are not sure.

Using pop()

pop() removes an element by position and hands it back to you.

Removing by position, and keeping the value

from array import array

marks = array("i", [78, 85, 60])

last = marks.pop()
first = marks.pop(0)

print("Removed from the end:", last)
print("Removed from the front:", first)
print("What is left:", marks)

With no number, pop() takes the last element. With a number, it takes that position.

Here are the two side by side, so the difference stands out:

remove()pop()
Works byvalueposition
Gives backnothingthe removed element
Not foundValueErrorIndexError
Use whenyou know the valueyou know the position, or want the value

After learning how to add, remove and change values, the next skill is finding them.

Searching in Arrays

Finding Elements with index()

index(value) gives the position of the first element equal to that value.

Finding a position

from array import array

marks = array("i", [78, 85, 60, 85])

print(marks.index(85))
print(marks.index(60))

It raises ValueError when the value is missing, so test first:

Looking before leaping

from array import array

marks = array("i", [78, 85, 60])

if 99 in marks:
    print("Found at", marks.index(99))
else:
    print("99 is not in the array")

Membership Testing

in answers whether a value is present, with no error and no position.

Just asking whether it is there

from array import array

marks = array("i", [78, 85, 60])

print(78 in marks)
print(99 in marks)
print(99 not in marks)

Use in when you want a yes or no, and index() when you need to know where.

Array Operations

These five operations are what every collection is judged on, in any language.

Traversing

Visiting every element once.

Traversal, and what it costs

from array import array

marks = array("i", [78, 85, 60, 92])

total = 0
for mark in marks:
    total += mark

print("Total:", total)
print("Elements visited:", len(marks))

Traversal always costs one step per element.

Insertion

There are two ways to add, and they behave differently:

Insertion at the end and in the middle

from array import array

marks = array("i", [78, 85, 60])

marks.append(92)
print("After append:", marks)

marks.insert(1, 100)
print("After insert at 1:", marks)

Appending is cheap. Inserting near the front means shifting everything after it.

Deletion

Three ways to delete

from array import array

marks = array("i", [78, 85, 60, 92])

marks.remove(85)
print("After remove(85):", marks)

marks.pop(0)
print("After pop(0):", marks)

del marks[0]
print("After del marks[0]:", marks)

del removes by position and gives nothing back, which is the difference from pop().

Search

Searching from front to back

from array import array

marks = array("i", [78, 85, 60, 92])
target = 60

for position, mark in enumerate(marks):
    if mark == target:
        print("Found", target, "at position", position)
        break
else:
    print(target, "is not here")

This is a linear search: look at each element until you find it. The worst case checks every element.

Update

Changing one element, and all of them

from array import array

marks = array("i", [78, 85, 60])

marks[0] = 80
print("One changed:", marks)

for position in range(len(marks)):
    marks[position] += 5

print("All raised by 5:", marks)

Changing one element is instant — Python jumps straight to that position.

Array Methods

An array carries its own set of methods. To add elements you have three choices, each for a different job.

append()

Adds one element to the end.

append

from array import array

marks = array("i", [78])
marks.append(85)
print(marks)

If you append a tuple or a list, the whole thing is added as one element.

extend()

Adds several elements to the end.

extend, and how it differs from append

from array import array

a = array("i", [78, 85])
a.extend([60, 92])
print("extend:", a)

b = array("i", [78, 85])
b.append(60)
print("append:", b)

append adds one thing. extend adds each item of a collection.

insert()

insert

from array import array

marks = array("i", [78, 60])
marks.insert(1, 85)
print(marks)

remove()

remove

from array import array

marks = array("i", [78, 85, 60])
marks.remove(85)
print(marks)

pop()

pop

from array import array

marks = array("i", [78, 85, 60])
print("Taken:", marks.pop())
print("Left:", marks)

index()

index

from array import array

marks = array("i", [78, 85, 60])
print(marks.index(60))

reverse()

Reverses the array in place — it changes the array and gives nothing back.

reverse changes the array itself

from array import array

marks = array("i", [78, 85, 60])

result = marks.reverse()

print("The array now:", marks)
print("What reverse() returned:", result)

result is None. Writing marks = marks.reverse() would throw the array away — a mistake worth meeting once.

tolist()

Converts the array into an ordinary list.

tolist

from array import array

marks = array("i", [78, 85, 60])
as_list = marks.tolist()

print(as_list, type(as_list).__name__)

as_list.append("absent")
print("A list accepts anything:", as_list)

Use it when you need something a list can do and an array cannot — mixing types, or handing the values to code that expects a list.

Here is the full set in one table:

MethodWhat it doesGives back
append(v)adds one element at the endnothing
extend(values)adds each item of a collectionnothing
insert(i, v)inserts before position inothing
remove(v)deletes the first element equal to vnothing
pop(i)deletes by positionthe removed element
index(v)position of the first va number
reverse()reverses in placenothing
tolist()copies into a lista new list

Most array methods change the array and return None. marks = marks.reverse() leaves you holding None with the array gone. Call it on its own line.

enumerate() Function

Getting Index and Value

Often you want both the position and the value. Doing it by hand needs a counter:

Keeping a counter by hand

from array import array

marks = array("i", [78, 85, 60])

position = 0
for mark in marks:
    print(position, mark)
    position += 1

enumerate() does that for you, and cannot forget to add 1:

enumerate does it for you

from array import array

marks = array("i", [78, 85, 60])

for position, mark in enumerate(marks):
    print(position, mark)

Using enumerate() in Loops

start= changes the first number, which is how you number things for people:

Numbering from 1 for a report

from array import array

marks = array("i", [78, 85, 60])
subjects = ["Maths", "Science", "English"]

for number, mark in enumerate(marks, start=1):
    print(number, subjects[number - 1], mark)

enumerate() works on anything you can loop over, not just arrays:

The same tool on a string and a list

for position, letter in enumerate("Asha"):
    print(position, letter)

for position, subject in enumerate(["Maths", "Science"]):
    print(position, subject)

Reach for enumerate() whenever you catch yourself writing range(len(...)). It is shorter, and the counter cannot drift out of step with the values.

Arrays work well with many of Python's built-in numeric functions. These functions can calculate totals, averages and other useful values without writing the loops yourself.

Numeric Functions

These are built in. They work on arrays, lists, and anything else you can loop over.

sum()

sum() adds up everything in a collection:

sum

from array import array

marks = array("i", [78, 85, 60])

print(sum(marks))
print(sum(marks) / len(marks))
print(sum(marks, 100))

The second number is where the total starts, which is occasionally useful and often surprising.

min() and max()

min() and max() find the ends of a collection, and both sides of a comparison:

min and max

from array import array

marks = array("i", [78, 85, 60])

print("Lowest:", min(marks))
print("Highest:", max(marks))
print("Range:", max(marks) - min(marks))

They work on text too, comparing character by character:

min and max on text

subjects = ["Maths", "Science", "English"]

print(min(subjects))
print(max(subjects))
print(max("Asha"))

max("Asha") is s, not A. Capital letters come before small ones in character order, so s is the largest character here.

round()

round

from array import array

averages = array("d", [78.456, 85.5, 60.249])

print(round(78.456, 2))
print(round(sum(averages) / len(averages), 1))
print(round(78.456))

With no second number, round() gives a whole number.

abs()

abs() gives the distance from zero, dropping any minus sign.

abs

marks_change = [-12, 5, -3]

for change in marks_change:
    print(change, "-> moved by", abs(change))

Useful whenever you care how much something changed, not which way.

pow()

pow(x, y) is x to the power of y — the same as x ** y.

pow

print(pow(2, 3))
print(2 ** 3)
print(pow(144, 0.5))
print(pow(2, 10, 1000))

The third number is a remainder step, used in cryptography. Treat it as a curiosity for now.

Here are all six in one table:

FunctionWhat it doesExampleResult
sum(values)adds them upsum([78, 85])163
min(values)smallestmin([78, 85])78
max(values)largestmax([78, 85])85
round(x, n)rounds to n placesround(78.456, 1)78.5
abs(x)distance from zeroabs(-12)12
pow(x, y)x to the power of ypow(2, 3)8

A small report built from the lot

from array import array

marks = array("i", [78, 85, 60, 92, 45])

print("Count:   ", len(marks))
print("Total:   ", sum(marks))
print("Average: ", round(sum(marks) / len(marks), 1))
print("Lowest:  ", min(marks))
print("Highest: ", max(marks))
print("Spread:  ", abs(max(marks) - min(marks)))

Common mistakes

Each row is one mistake. The middle column is what you will actually see on screen.

MistakeWhat you seeWhy it happensFix
Using the length as the last indexIndexError: array index out of rangeThe last index is one less than the lengthmarks[-1], or marks[len(marks) - 1]
Putting the wrong type inTypeError: 'float' object cannot be interpreted as an integerThe type code is enforcedMatch the code, or use d for decimals
A number too big for its codeOverflowErrorb holds up to 127Use a wider code such as i or q
Assigning the result of reverse()The array becomes NoneIt changes the array in place and returns nothingCall it on its own line
remove() for a value that is absentValueErrorremove() works by value and needs it presentCheck with in first
Confusing remove() with pop()The wrong element disappearsremove() takes a value, pop() a positionPick by what you actually know
append() where extend() was meantA collection added as one elementappend adds exactly one thingextend to add each item
Expecting remove() to delete every copyOnly the first one goesIt removes the first matchLoop, or rebuild the array
Forgetting the type codeTypeError: array() argument 1 must be a strThe code is not optionalarray("i", [...])
Changing an array while looping over itElements quietly skippedThe positions shift under the loopLoop over a copy, or build a new one

What to Remember

  • An array holds many values of the same kind, in order, each reachable by its position.
  • In Python you normally use a list. The array module is for storing a great many numbers compactly.
  • array(typecode, values) needs the type code, and the code is enforced.
  • The first index is 0, and the last index is one less than the length. marks[-1] is the last element.
  • A slice goes up to but not including its second number.
  • append() adds one element, extend() adds each item of a collection.
  • remove() works by value and returns nothing; pop() works by position and hands the element back.
  • index() gives a position and raises ValueError when the value is missing; in just answers yes or no.
  • Methods that change an array return None. Never write marks = marks.reverse().
  • enumerate() gives the position and the value together — reach for it instead of range(len(...)).
  • sum(), min(), max(), round(), abs() and pow() are built in and work on any collection.

Next: String Operations