Embercode
✕
ArraysLesson 1 of 17

45 min read

One-dimensional arrays in Python lists

Why arrays matter

Almost every interview question about data starts with an array. A list of prices, a row of exam marks, the heights of people in a photo: each one is an array. If you can read, change and walk through an array without thinking about the mechanics, your attention goes to the real problem. This lesson builds that comfort from zero.

Python does not have a separate array type for everyday work. You use the built-in list, written with square brackets, such as [70, 85, 90, 60]. A list holds values in a row, it is indexed from 0, and it can change size. The lists in this lesson play the role of the fixed-size arrays from other languages. The difference matters, and it is explained below.

Every program in this lesson runs as a plain Python file. You do not need functions or classes yet. The lesson uses only loops, if statements and lists.

The idea from first principles

Computer memory is a long strip of numbered cells. Each cell holds a small amount of data. When your program needs many values, it reserves a run of cells that sit next to each other. For a Python list, that run holds references, not the numbers themselves. You will see what that means in the section on references.

Think of a row of lockers in a school corridor. The first locker is number 0, the next is number 1, and so on. The number is fixed by position, not by what is inside. Each locker holds one thing.

Three words carry the whole idea.

  • Index: the position number of a box. Counting starts at 0, so the first box is index 0 and the second is index 1.
  • Length: how many boxes the list has. A list of five boxes has length 5, and its indexes run from 0 to 4.
  • Element: the value stored in one box. Some people say "item" or "entry" instead.

The picture of a row of boxes is useful, so keep it in mind while you read the code. A list of five numbers has five boxes side by side. The box at index 2 is two box-widths after the first box.

This layout explains the most important speed fact about arrays. To find box i, Python takes the address of the first box, adds i times the size of one box, and reads the result. That is one multiplication and one addition, whatever i is. Reading marks[4] costs the same as reading marks[0]. Computer scientists write this as O(1) time, meaning the cost does not grow with the size of the array. The complexity module explains this notation in full.

Creating a list

Python gives you several ways to make a list. The most direct one lists the values in square brackets.

Python · editable

Output:

[70, 85, 90, 60]
4

len(marks) returns the length. It is a function that takes the list as its input, so the call uses parentheses and the list goes inside them. This is different from the attribute length in some other languages, and the common mistakes section shows the error you get when you mix them up.

To make a list of a known size filled with the same value, multiply a list by a number.

Python · editable

Output:

[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The expression [0] * 5 means "the list [0] repeated five times". It makes a new list with five boxes, all holding 0. You can use a variable for the size, for example data = [0] * n, when the size comes from the user.

Unlike a fixed-size array in other languages, a Python list can grow and shrink. append adds one value at the end, and pop removes the last value. You do not have to know the size in advance. The list above would still work if you added values later. This is a real difference from the arrays in other languages, and it makes many beginner tasks shorter. The price is that the list uses slightly more memory than a fixed block would, and the next section shows the one place where that matters.

Default values

Python has no default value for a new box. You choose the starting value yourself. The usual choices are these.

Python · editable

Output:

[0, 0, 0]
[0.0, 0.0, 0.0]
[False, False, False]
[None, None, None]
['', '']

None is Python's word for "no value here". It plays the role of null in other languages. A list of names that starts full of None has room for names but holds none yet. The empty text "" is different from None. Calling len on "" gives 0, while calling len on None raises an error, which you will see later in this lesson.

Reading and changing boxes

To read or write a box, put the index in square brackets after the list name. marks[0] is the first box. marks[3] = 65 replaces the value in the fourth box. Writing to a box does not change the length, and it does not affect the other boxes.

Python · editable

Output:

70
[70, 85, 90, 65]
65

Python also allows negative indexes. marks[-1] means "the last box", marks[-2] means "the box before the last", and so on. Negative indexes count from the end. They are a convenience, but they do not replace a clear index. A loop that uses them by mistake can hide a bug, so use them when they make the code clearer.

The last valid positive index is always len(marks) - 1. For a list of four boxes, the last index is 3. This single fact causes most array bugs, so keep it in mind through the whole lesson.

Why does counting start at 0? An index is an offset from the start of the row, not a position number as people use in everyday speech. The first box is zero steps from the start, so its address is the start itself. The third box is two steps away. Counting from 1 would force every access to subtract 1 first, which is one more step to get wrong. Most languages you will meet, including C, C++, Java and JavaScript, count from 0 for the same reason. When a problem numbers things from 1, convert once when you read the input, and keep 0-based indexes inside the program.

Worked example 1: sum, largest and smallest

This program reads a line of numbers and prints three facts about them. It uses input(), which waits for you to type a line and press Enter. Save the program as main.py and run it with python3 main.py. Then type 70 85 90 60 65 and press Enter.

values = [int(x) for x in input().split()]
 
total = 0
largest = values[0]
smallest = values[0]
for v in values:
    total += v
    if v > largest:
        largest = v
    if v < smallest:
        smallest = v
 
print("Sum:", total)
print("Max:", largest)
print("Min:", smallest)

Output:

Sum: 370
Max: 90
Min: 60

Here is what each part does. input() returns the whole line as text. .split() breaks the text into pieces at each space, so "70 85 90 60 65" becomes the pieces "70", "85" and so on. int(x) turns each piece into a whole number. The list comprehension [int(x) for x in input().split()] does all of this in one line. It reads as "for each piece x, make int(x), and collect the results in a list".

Notice that the program does not ask for the count first. A Python list grows to fit whatever the line holds, so the count is not needed. A program written in a language with fixed-size arrays would read the count n first and create the array with that size. Both approaches are correct. The Python version is shorter because the list is resized as needed.

The loop for v in values: gives you one element per pass, starting at the first box. Use this form when you only need the values. Use for i in range(len(values)) when you need the position, for example to change a box or to compare a box with its neighbour.

Now trace the loop by hand. The numbers are 70, 85, 90, 60 and 65. The total starts at 0 and grows: 70, then 155, then 245, then 305, then 370. The largest starts at values[0], which is 70. Then 85 is bigger, so largest becomes 85. Then 90 is bigger, so it becomes 90. The values 60 and 65 are not bigger, so largest stays 90. For smallest, the start is 70. The values 85 and 90 are not smaller. The value 60 is smaller, so smallest becomes 60. The value 65 is not smaller, so it stays 60.

Why does largest start at values[0] and not at 0? Because the numbers might all be negative. If every value is -5, a starting maximum of 0 would print 0, which is not in the list at all. Starting from a real element is always safe when the list has at least one element.

Python also has built-in functions for these three facts. sum(values) gives the total, max(values) gives the largest value and min(values) gives the smallest. Use them in real code. The loop above shows the logic that they hide.

Python · editable

Output:

370 90 60

What happens with an empty list? Then values[0] raises an error, because there is no box zero. max([]) also raises an error, with a different message. The edge cases section near the end of the lesson covers this in detail.

Worked example 2: reversing in place

Reversing means putting the values in the opposite order. The simple way is to make a second list and copy the values backwards. The better way is to swap boxes inside the same list. "In place" means the work happens inside the list you already have, without a second list of the same size.

The method is called two pointers, and the lesson on prefix sums covers it fully. Here it is in its simplest form. One index starts at the left end, the other at the right end. Swap the two boxes, then move both indexes one step toward the middle. Stop when they meet or cross.

Picture the boxes of [1, 2, 3, 4, 5, 6] after the first swap. The 1 and the 6 trade places, then the 2 and the 5, then the 3 and the 4.

Python · editable

Output:

[6, 5, 4, 3, 2, 1]

The line a[left], a[right] = a[right], a[left] swaps two values without a third variable. Python first builds the right-hand side as a pair of values, (a[right], a[left]), and only then assigns them. In most other languages you need a temporary variable to do this. Picture two cups of juice, one orange and one apple. You cannot pour the orange into the apple cup and then pour the apple into the orange cup, because the apple juice is gone after the first pour. The pair assignment works like an empty cup that Python provides for you. If you want the explicit version, write temp = a[left] first, then a[left] = a[right], then a[right] = temp.

Trace the first two passes for [1, 2, 3, 4, 5, 6]. In the first pass, left is 0 and right is 5. The values 1 and 6 swap, so the list becomes [6, 2, 3, 4, 5, 1]. Then left becomes 1 and right becomes 4. The values 2 and 5 swap, giving [6, 5, 3, 4, 2, 1]. The third pass swaps 3 and 4 and gives [6, 5, 4, 3, 2, 1]. Then left is 3 and right is 2, so left < right is false and the loop stops.

The loop does not need to handle the middle element when the length is odd. In a list of five, the middle box is at index 2. When left and right both reach 2, they are equal, the test left < right fails, and the loop ends without touching it. That is correct, because the middle box does not move.

The work is O(n) time: each box is touched about once. The extra memory is only left and right, which does not grow with n. That is O(1) extra space. Interviewers often ask for exactly this pair of facts, so state both when you explain a solution.

Python also has a built-in method for this. a.reverse() reverses the list in place and returns nothing. a[::-1] makes a new reversed copy and leaves a alone. The slice a[::-1] is covered in the next lesson.

Worked example 3: copying, filling and comparing

Python lists come with a few everyday operations that the next example uses. This program shows them side by side.

Python · editable

Output:

[3, 1, 2]
[3, 1, 2]
[99, 1, 2]
[3, 1, 2, 0, 0]
[7, 7, 7]
True
False

print(a) shows the list in a readable form, such as [3, 1, 2]. Python prints the contents for you. Other languages print a code for the object, which is not useful, so you need a helper for that.

a.copy() makes a true copy of the outer list. Changing b[0] leaves a alone, which the output confirms. The + operator joins two lists into a new list, so a + [0, 0] adds two boxes at the end without changing a.

[7] * len(a) builds a new list of 7s with the same length as a, and the name a now points to that new list. It is the usual way to reset a counting list before reusing it. If you want to change the existing list in place instead, write a[:] = [7] * len(a).

The last two lines show the difference between two kinds of equality. The == operator compares contents, so two lists with the same values are equal, and it prints True. The is operator compares identity, meaning whether the two names refer to the same object. Two separately created lists are never is each other, so it prints False, even though their boxes hold the same numbers. Use == to compare values. Use is only to check for None, as in if x is None.

Worked example 4: catching an index error

Python checks every index at run time. If you ask for a box that does not exist, Python stops the program with an error. This is a safety feature. Without it, the program would read the wrong value, or crash in a confusing place, with no clear message.

The error is called IndexError. The message says "list index out of range", which means the index is outside the allowed range.

This program catches the error so you can see its message. The try and except words mean "try this code, and if this particular error happens, run the code in the except block instead of stopping". You will learn the full rules later. For now, read it as "if the box does not exist, print a message".

Python · editable

Output:

Caught: list index out of range
The program keeps going

The message does not name the index or the length, so you need to check the code yourself. The index was 5 and the list has length 5. The valid indexes for a length of 5 are 0 to 4, so index 5 is one step past the end. When you see this message in a real program, find the loop or expression that produced the bad index. Almost always it is a loop that uses range(len(a) + 1) where it should use range(len(a)), or an index that was computed from the wrong variable.

If you do not catch the error, Python prints a traceback, which is a report of where the error happened. Save this program as main.py and run it.

a = [10, 20, 30, 40, 50]
print(a[5])

The output is:

Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print(a[5])
          ~^^^
IndexError: list index out of range

Read a traceback from the bottom. The last line is the error. The line above it names the file, the line number and the code that failed. The small ~^^^ marks under the code point at the part that failed, here the a[5]. Read the last line for the reason and the file line for the place.

Finding a value

A very common job is to ask, "Is this value in the list, and where?" Python gives you two ways to ask, and the first is the simplest.

The in operator answers "is it there?" with True or False. The index method answers "where is it?" with a position. It raises an error when the value is missing, so check with in first, or catch the error.

Python · editable

Output:

True
False
1

a.index(8) returns 1, the position of the first match. The value 8 appears twice, at indexes 1 and 6, and index stops at the first. If the value is missing, a.index(99) raises ValueError: list.index(x): x not in list. Test with in before you call index when the value might be absent.

Linear search

Linear search looks at the boxes from left to right until it finds the target. It works on any list, sorted or not. In the worst case it looks at every box, so it costs O(n) time. The in operator and index method both do a linear search inside Python. Writing the loop by hand shows how the search works.

Python · editable

Output:

1

The value 8 appears twice, at indexes 1 and 6. The program prints 1, the first match. The break statement stops the loop at the first match, so the second 8 is never checked. The variable found starts at -1. If the target never appears, found stays -1. This is a common convention: a negative index is not a real position, so it signals "not found".

If you change the target to 99, the output is -1. Try it in your head before you run it, and then check your answer.

Binary search

If the list is sorted, you can do much better. Binary search looks at the middle box. If the middle value equals the target, you are done. If the target is smaller, it must be in the left half, so you throw the right half away. If it is larger, you throw the left half away. Each step halves the remaining range. A list of a million sorted values needs at most about 20 steps.

Binary search needs two boundaries, low and high, and one middle index, mid. The middle index is (low + high) // 2. The double slash // is floor division, which divides and rounds down to a whole number, so (0 + 7) // 2 is 3. A single slash / would give a decimal, 3.5, and an index must be a whole number.

Watch the low and high boundaries move as you read the trace below. Each step removes half of the remaining boxes.

Python · editable

Output:

5

Trace it. The list has 8 boxes, so low is 0 and high is 7. The middle is (0 + 7) // 2 = 3, and a[3] is 12. The target 23 is bigger, so low becomes 4. The new middle is (4 + 7) // 2 = 5, and a[5] is 23. That matches, so result becomes 5.

Notice the condition low <= high. It uses <=, not <, because a range with one box left, where low equals high, still needs checking. Binary search gets its bugs from exactly this place, so be careful with it. The complexity module shows why the work is O(log n).

Python's standard library already has this search in the bisect module. bisect_left(a, 23) returns 5 for the same list, and it returns the place where the value would go if it were missing. You will use it in real code. Write the loop yourself once so that you understand what it does.

Python · editable

Output:

5
3

The second value, 3, is where 10 would be inserted to keep the list sorted. It is not a match, so check a[3] == 10 before you trust the answer.

The catch is that binary search is only correct on sorted data. If the list is not sorted, the "throw half away" step can throw away the answer, and the program can report -1 for a value that is present.

What happens inside the computer

When you write marks = [70, 85, 90, 60], Python does two things. It creates the list object, which holds four boxes. It also creates a name marks that points to the list. The boxes do not hold the numbers directly. Each box holds a reference, which is a small value that says where an object sits in memory. Think of a note that says "the row of lockers is in corridor C, room 12". The note is cheap to copy. The lockers are the large part.

Every number in Python is an object, and the list stores a reference to each one. This is why a list can hold values of different kinds, such as [1, "two", 3.0]. It is also why a list uses more memory than a row of plain numbers would. For this course, the detail that matters is the next point.

This explains the aliasing trap. When you write b = a, Python copies the note, not the list. Both names point at the same list. A change made through either name is visible through the other, because only one list exists.

Python · editable

Output:

[50, 2, 3]
True

The name b is a second label on the same list. To make an independent copy, write b = a.copy() or b = a[:], as the previous example showed.

Python does not free memory by hand. When no name refers to an object any more, Python reclaims it. Most of the time this happens at once, because Python counts how many names point to each object and frees it when the count reaches 0. A small cycle of objects that point at each other is cleaned up by a separate garbage collector. For array work you rarely think about this. The pointers and memory module shows the same picture in C++, where you see the addresses directly.

The same picture explains how functions receive lists. A function that receives a list receives a reference to it, not a copy. A function that changes a[0] changes the caller's list too. Beginners often find this surprising, so test it once.

Python · editable

Output:

[99, 85, 90]

Passing a list costs the same however long the list is, because only the reference is passed. A function that receives a list with ten million values does not make a copy of it. If a function must not change the caller's list, it should work on a copy, for example items = list(items) at the start.

Lists of objects

A list can hold any kind of object, not only numbers. The line names = [None] * 3 makes three boxes that each hold a reference to nothing yet. The list has room for three names, but it holds no text. You must fill each box before you use it.

Python · editable

Output:

4
True

The first line prints 4, the length of "Asha". The second line prints True, because box 2 was never filled. If you call len(names[2]) instead, Python raises a TypeError, which means you used a value in a way its type does not allow. A safe loop checks names[i] is not None before it uses the value, or it fills every box before the loop starts.

The same rule applies to any object type. A list of your own objects starts with None in each box until you create each object yourself.

Reading large input

The input() function reads one line at a time. It is simple, and it is fine for a few thousand numbers. For inputs with hundreds of thousands of numbers, it becomes slow, because each call handles one line. A faster approach reads all of the input at once with sys.stdin.read() and splits it into pieces.

import sys
 
data = sys.stdin.read().split()
n = int(data[0])
values = [int(x) for x in data[1:1 + n]]

This reads every whitespace-separated token, so the numbers can be on one line or several. data[0] is the count, and data[1:1 + n] takes the next n tokens. The slice data[1:1 + n] is a new list that holds those tokens. The slice rule is explained in the next lesson.

Notice that the numbers arrive as text. int(x) turns one piece of text into a whole number. The function input() raises EOFError at the end of the input, so a careful program checks for that before it reads another line. The sys.stdin.read() version avoids the problem, because it reads everything at once and returns an empty string when there is nothing left.

Common mistakes

These are the mistakes beginners make most often with lists used as arrays. Each one has a real error message, and you should learn to recognise them.

1. Using <= in a loop over the length. This loop runs one step too far.

a = [1, 2, 3, 4, 5]
for i in range(len(a) + 1):
    print(a[i])

The output shows the five real numbers, and then the program crashes:

1
2
3
4
5
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(a[i])
          ~^^^
IndexError: list index out of range

The fix is range(len(a)). The index that goes past the end is the one that is equal to the length. Even better, when you only need the values, write for v in a: and avoid indexes altogether.

2. Writing length on a list. Lists use the function len(a). A list has no attribute named length, so this is an error:

a = [1, 2, 3]
print(a.length)
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print(a.length)
          ^^^^^^^^
AttributeError: 'list' object has no attribute 'length'

Replace it with len(a). The message names the problem exactly: there is no attribute named length on a list.

3. Copying with =. The line b = a does not copy the list. It gives the same list a second name. Changing b[0] also changes a[0]. When you need a real copy, use a.copy(), a[:] or list(a).

4. Making a grid with repeated rows. This looks like it makes a 2 by 3 grid of zeros, but it does not.

Python · editable

Output:

[[0, 5, 0], [0, 5, 0]]

The outer list holds the same inner list twice, so both rows change together. Build each row separately: grid = [[0] * 3 for _ in range(2)]. The two-dimensional arrays lesson covers this in full.

5. Comparing lists with is. Two lists with the same numbers are not is each other unless they are the same object. Use == to compare contents.

Python · editable

Output:

True
False

6. Forgetting that a list has a fixed range of indexes. Python lists grow with append, but the index you use must already exist. Writing a[5] = 1 on a list of four boxes raises an error. Use a.append(1) to add a new box at the end.

a = [1, 2, 3, 4]
a[4] = 9
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    a[4] = 9
    ~^^^
IndexError: list assignment index out of range

7. Reading the first box of an empty list. [] has no boxes, so a[0] raises IndexError. Check if len(a) == 0 before reading a[0] whenever the input might be empty.

Python · editable

Output:

empty

8. Expecting None to be empty text. A list of names that starts with None has no text in it. Calling len(names[0]) on a None box raises TypeError. Fill the list with real text before you use it, or check for None first.

names = [None] * 2
print(len(names[0]))
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    print(len(names[0]))
          ~~~^^^^^^^^^^
TypeError: object of type 'NoneType' has no len()

Debugging walkthrough

Here is a realistic bug. A teacher wants the total of the marks, and the program prints a wrong total.

Python · editable

Output:

Total: 235

The correct total is 305. The output is 70 short, because the first mark is missing. Work through the code the way a careful programmer would. Start by asking what the loop should visit. It should visit every index from 0 to 3. The loop starts at 1, so it skips index 0. That is the bug. The fix is to start the loop at 0, or to loop over the values directly with for m in marks.

Now check the fix with a small case you can do by hand. For [5], the total should be 5. With the start at 1, the loop does not run, and the total is 0. With the start at 0, the loop runs once and the total is 5. A one-element list is the best test for a loop boundary, because it is the smallest case where the boundaries touch.

This method is worth repeating on every bug. Name what the code should do, find where it differs from that, and test the smallest input that shows the difference.

Variations and edge cases

Interviewers like to ask about edge cases, because they show how carefully you think. For one-dimensional arrays, the edge cases are almost always the same.

The empty list. A loop over range(len(a)) does not run when the list is empty, which is correct. But reading a[0] raises IndexError, and max(a) raises ValueError. Decide what the answer should be for an empty input before you write the code, and then write that branch first.

One element. Many loops and two-pointer patterns need care when there is one element, because left and right are the same box. The reverse program above handles it correctly, because left < right is false from the start.

All values equal. For a maximum or minimum search, starting from a[0] works. For a search that compares neighbours, equal values are a common source of bugs when the rule says "strictly greater".

Negative values. Never start a maximum at 0 unless you know the values are not negative. The same trap appears in the Kadane lesson.

Very large values. Python integers do not overflow. The integer type grows to hold any size of whole number, so a sum of large values stays correct. Other languages wrap around to a wrong negative number when the value is too big for a fixed-size integer. In Python this does not happen, but very large numbers take more memory and more time to add.

Python · editable

Output:

4000000000
1267650600228229401496703205376

Python gives the exact answer in both lines. A language with a 32-bit int would print a wrong negative number for the first line. Keep this difference in mind when you read the Java or C++ lessons of the course.

Real-world uses

Arrays are everywhere in ordinary software. A photo is a grid of pixel values, and each row is a one-dimensional array. A sound recording is a long array of samples. A game stores the scores of its players in a list. A shop stores the prices of the day in a list indexed by day.

The reason arrays dominate is the O(1) access described earlier. When a program must look up item i thousands of times per second, a direct index is the fastest tool the computer has. The Python list gives you that access and also lets the list grow, so it covers most of the work that fixed-size arrays do elsewhere. For heavy numeric work on large grids, libraries such as NumPy store values in a fixed-size block, which is closer to the array idea described at the start of this lesson.

What interviewers ask about arrays

Here are the questions that come up most often at this level, with the answers an interviewer wants to hear.

"What is the time to read a[i]?" Answer: O(1), because the address is computed directly from the index.

"What is the time to find a value in an unsorted list?" Answer: O(n), by linear search, because in the worst case you check every box. The in operator does this.

"Why is binary search faster, and what must be true first?" Answer: each step halves the range, so it takes about log base 2 of n steps. The list must be sorted, otherwise discarding half can throw away the answer.

"How do you reverse an array in place?" Answer: two pointers from the ends, swapping as they move inward. It takes O(n) time and O(1) extra space.

"What happens with an empty input?" Answer: name the case, return the agreed value, and do not read a[0].

A strong answer names the cost, names the condition the method depends on, and handles the empty case without being asked.

Practice

Try these before you read the answers. Save each program as main.py and run it with python3 main.py. Each answer is shown after a "Show the answer" line.

  1. Write a program that reads a line of numbers and prints the smallest value. Test it with the input 4 -2 9. The answer is -2.

Show the answer

values = [int(x) for x in input().split()]
smallest = values[0]
for v in values[1:]:
    if v < smallest:
        smallest = v
print(smallest)

The loop starts from the second value, because smallest already holds the first. Starting from the first value would also work, and it would compare the first value with itself, which is harmless. The slice values[1:] is a new list without the first box.

  1. Count how many even numbers are in [4, 7, 10, 3, 8]. The answer is 3. (Hint: a number is even when value % 2 == 0.)

Show the answer

Python · editable

The % operator gives the remainder after division. A remainder of 0 means the value divides by 2 exactly, so it is even. The output is 3, because 4, 10 and 8 are even.

  1. Rotate a list one step to the left. [1, 2, 3, 4] becomes [2, 3, 4, 1]. Save a[0] first, shift every other value one place left, then put the saved value at the end.

Show the answer

Python · editable

The output is [2, 3, 4, 1]. The loop stops at len(a) - 2, because a[i + 1] must stay inside the list. Without saving first, the value 1 would be overwritten before it could move to the end. Python has a shorter way, a = a[1:] + a[:1], which builds a new list. Both give the same answer.

  1. Given [2, 5, 9], create a new list with every value doubled, and print both the original and the new list. The original must not change.

Show the answer

Python · editable

The output is [2, 5, 9] and then [4, 10, 18]. Writing doubled = original and then changing it would also change original, because both names point to the same list. The list comprehension builds a new list, so the original is left alone.

  1. Print the index of the largest value in [3, 9, 2, 9, 7]. If the largest value appears more than once, print the first index. The answer is 1.

Show the answer

Python · editable

The test is >, not >=. With >=, the second 9 at index 3 would replace index 1, and the program would print 3. Keeping the first match needs the strict comparison.

  1. Check whether two lists have the same values in the same order, without using ==. Test it with [1, 2, 3] against [1, 2, 3] (True) and against [1, 3, 2] (False). Check the lengths first.

Show the answer

Python · editable

The output is True and then False. The length check must come first. Comparing a[i] with b[i] when b is shorter would raise IndexError. The function same returns early, which is why each return sits inside the loop.

  1. Read n on the first line and the values on the second line. Print only the values that are strictly greater than the average. Do not use decimals. Compare value * n with the sum. The input 5 then 2 4 6 8 10 prints 8 and 10.

Show the answer

n = int(input())
values = [int(x) for x in input().split()]
total = sum(values)
for v in values:
    if v * n > total:
        print(v)

A value is greater than the average exactly when v > total / n. Multiplying both sides by n avoids decimals, and a Python integer never overflows, so the sum needs no special type.

  1. Find the second-largest value in [5, 9, 9, 3]. The answer is 5, because a repeated maximum does not count as a second value. If all values are equal, print none.

Show the answer

Python · editable

This tracks the largest and the second-largest distinct values in one pass. The value None means "not seen yet". The output is 5. A shorter version, sorted(set(a))[-2], also gives 5, but it fails with IndexError when there are fewer than two distinct values, and it sorts the whole list first.

  1. Move every zero to the end of a list while keeping the other values in their original order. [0, 4, 0, 7, 1] becomes [4, 7, 1, 0, 0]. Use one pass, and do not create a second list.

Show the answer

Python · editable

The read index scans every box. The write index marks where the next non-zero value goes. Copying non-zero values forward keeps their order, and the leftover boxes at the end become zero. The output is [4, 7, 1, 0, 0].

  1. Prove that b = a does not copy. Set a = [1, 2, 3], make b = a, change b[0] to 50, and print a. The output must be [50, 2, 3].

Show the answer

Python · editable

Both names point to one list, so changing it through b changes what a shows. To get an independent copy, write b = a.copy() instead.

What you now know

  • A Python list is a row of boxes next to each other, numbered from index 0. Use it as the array in most programs.
  • Reading or writing a[i] takes O(1) time, because Python computes the address from the index.
  • The last valid index is len(a) - 1. Use len(a) for the length, not a.length.
  • A list can grow with append and shrink with pop. Its boxes hold references, so b = a gives a second name for the same list.
  • Use in, index, copy, [value] * n and == for everyday work. Use is only for None and for identity checks.
  • Linear search checks each box in O(n) time. Binary search needs sorted data and takes O(log n) time. The bisect module does the second one for you.
  • Read a traceback from the bottom, and find the index and the length that the error refers to.
Practice this topic: coding problems for Arrays →

Stuck? Ask the tutor

Ask about anything in this lesson. Answers are short and use simple words.

Sign in to ask the tutor.