It's amortized O(1), not O(1).

Let's say the list reserved size is 8 elements and it doubles in size when space runs out. You want to push 50 elements.

The first 8 elements push in O(1). The nineth triggers reallocation and 8 copies, followed by an O(1) push. The next 7 push in O(1). The seventeenth triggers reallocation and 16 copies, followed by an O(1) push. The next 15 push in O(1). The thirty-third triggers reallocation and 32 copies, followed by an O(1) push. The next 31 push in O(1). This continues as the size of list is doubled again at pushing the 65th, 129th, 257th element, etc..

So all of the pushes have O(1) complexity, we had 64 copies at O(1), and 3 reallocations at O(n), with n = 8, 16, and 32. Note that this is a geometric series and asymptotically equals O(n) with n = the final size of the list. That means the whole operation of pushing n objects onto the list is O(n). If we amortize that per element, it's O(n)/n = O(1).

Answer from rlbond on Stack Overflow
Top answer
1 of 3
209

It's amortized O(1), not O(1).

Let's say the list reserved size is 8 elements and it doubles in size when space runs out. You want to push 50 elements.

The first 8 elements push in O(1). The nineth triggers reallocation and 8 copies, followed by an O(1) push. The next 7 push in O(1). The seventeenth triggers reallocation and 16 copies, followed by an O(1) push. The next 15 push in O(1). The thirty-third triggers reallocation and 32 copies, followed by an O(1) push. The next 31 push in O(1). This continues as the size of list is doubled again at pushing the 65th, 129th, 257th element, etc..

So all of the pushes have O(1) complexity, we had 64 copies at O(1), and 3 reallocations at O(n), with n = 8, 16, and 32. Note that this is a geometric series and asymptotically equals O(n) with n = the final size of the list. That means the whole operation of pushing n objects onto the list is O(n). If we amortize that per element, it's O(n)/n = O(1).

2 of 3
61

If you look at the footnote in the document you linked, you can see that they include a caveat:

These operations rely on the "Amortized" part of "Amortized Worst Case". Individual actions may take surprisingly long, depending on the history of the container.

Using amortized analysis, even if we have to occasionally perform expensive operations, we can get a lower bound on the 'average' cost of operations when you consider them as a sequence, instead of individually.

So, any individual operation could be very expensive - O(n) or O(n^2) or something even bigger - but since we know these operations are rare, we guarantee that a sequence of O(n) operations can be done in O(n) time.

๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ what is python's list.append() method worst time complexity? it can't be o(1), right?
r/learnpython on Reddit: What is Python's list.append() method WORST Time Complexity? It can't be O(1), right?
October 26, 2022 -

I know that lists in Python are implemented using arrays that store addresses to the information. Therefore, after several appends, when an array is loaded, it needs to reserve a new space and copy the entire array of addresses to the new place.

I've read on Stackoverflow that in Python Array doubles in size when run of space. So basically it has to copy all addresses log(n) times.

The bigger the list, the more copying it will need to do. So how can append operation have a Constant Time Complexity O(1) if it has some dependence on the array size

I assume since it copies addresses, not information, it shouldn't take long, python takes only 8 bytes for address after all. Moreover, it does so very rarely. Does that mean that O(1) is the average time complexity? Is my assumption right?

Top answer
1 of 4
4
I've read on Stackoverflow that in Python Array doubles in size when run of space It's actually not double, but it does increase proportional to the list size (IIRC it's about 12%, though there's some variance at smaller sizes). This does result in the same asymptotics though, so I'll assume doubling in the following description for simplicity. So basically it has to copy all addresses log(n) times. Not quite. Suppose we're appending n items to an empty vector. We will indeed do log(n) resizes, so you might think "Well, resizes are O(n), so log(n) resizes is n log(n) operations, which if we amortize over the n appends we did means n log(n)/n, or log(n) per append". However, there's a flaw in this analysis: we do not copy "all addresses" each of those times. Ie. the copies are not O(n). Sure, the last copy we do will involve copying n items, but the one before it only copied n/2, and so on. So we actually do 1 + 2 + 4 + ... + n copies, which sums to 2n-1. Divide that by n and you get ~2 operations per append - a constant. I assume since it copies addresses, not information We are indeed only copying the pointer, but this doesn't really matter for the complexity analysis. Even if it was copying a large structure, that'd only increase the time by a constant factor. Does that mean that O(1) is the average time complexity? It's the amortized worst case complexity (ie. what happens over a large number of operations). While any one operation can indeed end up doing O(n) operations, there's an important distinction that over a large number of operations, you are guaranteed to only be O(1), which is a distinction just talking about average case wouldn't capture.
2 of 4
2
Personally, I thought that lists worked as double LinkedLists, so insert time was O(1) But if it works as a dynamic array, time complexity should be amortized time, ie, close to O(1) but not quite
Discussions

python - Time complexity of appending a list to a list - Stack Overflow
I understand the amortized complexity of appending an element to a list is O(1) but what is the time complexity of appending a list to a list? For clarification: Appending an element to a list list... More on stackoverflow.com
๐ŸŒ stackoverflow.com
Briefly explain the time complexity of the list.append() method.
Briefly explain the time complexity of the list.append() method. More on chegg.com
๐ŸŒ chegg.com
1
September 15, 2022
Time Complexity of Python list comprehension then list[i] = value vs. list = [] then list.append(value)
In terms of Big O the algorithms are equivalent to each other as they both have linear growth. As you say, the list comprehension in the first example is O(n) so the function is O(2n), but in algorithmic analysis that is considered equivalent to O(n). In practical terms the second approach is better as it only requires one iteration over the input array. More on reddit.com
๐ŸŒ r/learnprogramming
5
2
September 26, 2021
python - What is the time complexity for appending an element to a list? - Stack Overflow
What is the time complexity for appending an element to a list in Python? More on stackoverflow.com
๐ŸŒ stackoverflow.com
๐ŸŒ
LabEx
labex.io โ€บ tutorials โ€บ python-what-is-the-time-complexity-of-list-append-and-remove-operations-in-python-397728
What is the time complexity of list append and remove operations in Python | LabEx
For example, the time complexity of the Python list.append() operation is O(1), which means that the operation takes a constant amount of time, regardless of the size of the list.
๐ŸŒ
Scaler
scaler.com โ€บ home โ€บ topics โ€บ python โ€บ append in python
Python List append() Method with Examples - Scaler Topics
May 16, 2023 - In that scenario, the previous elements are copied to this new memory space, and new elements are appended to the list. So, this is considered as the worst case for appending any element to the list and the time complexity for this worst case is O(N) where N is the size of the original list.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ time-complexity-for-adding-element-in-python-set-vs-list
Time Complexity for Adding Element in Python Set vs List - GeeksforGeeks
July 23, 2025 - When we add an element to a list using the append() method, Python directly adds the element to the end. This operation has O(1) amortized time complexity, as no hashing or duplicate checks are needed.
Find elsewhere
๐ŸŒ
Python
wiki.python.org โ€บ moin โ€บ TimeComplexity
TimeComplexity - Python Wiki
Internally, a list is represented as an array; the largest costs come from growing beyond the current allocation size (because everything must move), or from inserting or deleting somewhere near the beginning (because everything after that must move).
๐ŸŒ
YouTube
youtube.com โ€บ anthonywritescode
how is list append possibly O(1)? (beginner - intermediate) anthony explains #466 - YouTube
today I go over how list / vector / arraylist is O(1) -- or well "amortized" O(1) and what that means!playlist: https://www.youtube.com/playlist?list=PLWBKAf
Published: August 22, 2022
Views: 3K
๐ŸŒ
Reddit
reddit.com โ€บ r/learnprogramming โ€บ time complexity of python list comprehension then list[i] = value vs. list = [] then list.append(value)
r/learnprogramming on Reddit: Time Complexity of Python list comprehension then list[i] = value vs. list = [] then list.append(value)
September 26, 2021 -

Let's say we are writing a function that we know the length of the output list == length of the input list. All we need to do is to insert some value to the output list and return it. I'd like to know if one approach's time complexity is better than another?

First approach:

def someFunc(inputArray):
    result = [1 for _ in inputArray]
    for i in range(len(inputArray)):
        someValue = 100
        result[i] = someValue

vs.

def someFunc(inputArray):
    result = []
    for i in range(len(inputArray)):
        someValue = 100
        result.append(someValue)

The first approach `result[i] = someValue` is O(1) operation, however, is is list comprehension O(n) ? if that's the case then the overall algorithm would be O(2n) time?

The second approach `result.append(someValue)` can be view as O(1) ? That leads to the overall algo time complexity O(n)?

Does that mean in terms of time complexity, second approach is better than first approach? Or not?

Top answer
1 of 3
4
In terms of Big O the algorithms are equivalent to each other as they both have linear growth. As you say, the list comprehension in the first example is O(n) so the function is O(2n), but in algorithmic analysis that is considered equivalent to O(n). In practical terms the second approach is better as it only requires one iteration over the input array.
2 of 3
1
Yes, the Time Complexity of the list comprehension is O(n). You literally iterate over every list element, so if the list has n elements, then you're doing n iterations. It's going to be a little more efficient than a for a loop though. Because it's implemented in the C language and better optimized But if we are talking about Asymptotic Growth(which Big O is about). Then the Time Complexity is going to be the same for both the for loop and the list comprehension. As for the actual code you sent. In the first version, you're literally iterating over a list two times. Which kind of doesn't make sense, you could just do [100 for _ in inputArray] and omit the second loop. You can even call functions, use if-else statements from the list comprehensions, and many other things But to answer your question directly, yes it's time Complexity is n+n or O(2n). BUT 2 is constant, which isn't going to affect the Complexity Growth much. Therefore it's not considered, since it doesn't matter that much. So Asymptotic Growth is still considered O(n) With the second version, your assumption is right. Appending to the list has a time complexity of O(1). Since the list size doesn't matter for this operation. Just for your information, removing elements from the list is a very different matter. If you're removing by value or by index from the list, this operation has the worst time complexity of O(n). Because if you removed the first element for example, then under the hood, the computer has to move every single element(n-1 elements) to the left. But it's not the case with the append operation, since you simply add a new element to the end of the list and nothing else is moving. Poping the last element is also O(1) since you just remove one element from the end, and everything stays where it is
๐ŸŒ
Runestone Academy
runestone.academy โ€บ ns โ€บ books โ€บ published โ€บ pythonds3 โ€บ AlgorithmAnalysis โ€บ Lists.html
2.6. Lists โ€” Problem Solving with Algorithms and Data Structures 3rd edition
From the experiment above it is clear that the append operation at 0.31 milliseconds is much faster than concatenation at 6.54 milliseconds. We also show the times for two additional methods for creating a list: using the list constructor with a call to range and a list comprehension.
๐ŸŒ
sqlpey
sqlpey.com โ€บ python โ€บ why-python-list-append-time-complexity
Top 5 Reasons Why Python's List Append Method Has O(1) Amortized Time Complexity
November 24, 2024 - Explore the reasons behind Python's list append method achieving O(1) time complexity and how amortized analysis plays a crucial role.
๐ŸŒ
Finxter
blog.finxter.com โ€บ home โ€บ learn python blog โ€บ python list append() method
Python List append() Method - Be on the Right Side of Change
June 19, 2021 - By using the list concatenation operation, you can create a new list rather than appending the element to an existing list. Time Complexity: The append() method has constant time complexity O(1).
๐ŸŒ
Unstop
unstop.com โ€บ home โ€บ blog โ€บ python list append() | syntax & working (with example codes)
Python List append() | Syntax & Working (With Example Codes)
February 4, 2025 - Time Complexity: The time complexity of the append() method is O(1), which means it operates in constant time. In most cases, appending an element takes the same amount of time, regardless of the size of the list.
๐ŸŒ
Quora
quora.com โ€บ What-are-the-time-complexity-considerations-of-lists-in-Python
What are the time complexity considerations of lists in Python? - Quora
Answer: In a normal list on average: * Append : O(1) * Extend : O(k) - k is the length of the extension * Index : O(1) * Slice : O(k) * Sort : O(n log n) - n is the length of the list * Len : O(1) * Pop : O(1) - pop from end * Insert : O(n) - n is the length of the list * Del : O(n) - n...
Top answer
1 of 1
27

I'll expand my comment a bit. The List[T] data structure, from scala.collection.immutable is optimized to work the way an immutable list in a more purely functional programming language works. It has very fast prepend times, and it is assumed that you will be working on the head for almost all of your access.

Immutable lists get to have very fast prepend times due to the fact that they model their linked lists as a series of "cons cells". The cell defines a single value, and a pointer to the next cell (classic singly-linked-list style):

Cell [Value| -> Nil]

When you prepend to a list, you're really just making a single new cell, with the rest of the existing list being pointed to:

Cell [NewValue| -> [Cell[Value| -> Nil]]

Because the list is immutable, you're safe to do this without any actual copying. There's no danger of the old list changing and causing all the values in your new list to become invalid. However, you lose the ability to have a mutable pointer to the end of your list as a compromise.

This lends itself very well to recursively working on lists. Let's say you defined your own version of filter:

def deleteIfT(f : T => Boolean): List[T] = list match {
  case Nil => Nil
  case (x::xs) => f(x) match {
    case true => deleteIf(xs)(f)
    case false => x :: deleteIf(xs)(f)
  }
}

That's a recursive function that works from the head of the list exclusively, and takes advantage of pattern matching via the :: extractor. This is something you see a lot of in languages like Haskell.

If you really want fast appends, Scala provides a lot of mutable and immutable data structures to choose from. On the mutable side, you might look into ListBuffer. Alternatively, Vector from scala.collection.immutable has a fast append time.

๐ŸŒ
Cuni
ksvi.mff.cuni.cz โ€บ ~dingle โ€บ 2022-3 โ€บ algs โ€บ notes_5.html
Introduction to Algorithms, 2022-3 Week 5: Notes
It will run in O(1) in the average case. Specifically, if we begin with an empty list and append a value to it N times, then the total running time will be O(N), so the average time per append will be O(N) / N = O(1).