Python Language List: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(19 intermediate revisions by the same user not shown)
Line 65: Line 65:
</syntaxhighlight>
</syntaxhighlight>
==Create a List of Specific Size==
==Create a List of Specific Size==
To create a list of specific size, so arbitrary elements can be set in place with <code>[[#Insert_an_Element_in_the_Middle_of_a_List|insert(offset, element)]]</code>, use this syntax:
To create a list of specific size, so arbitrary elements can be set in place at a specific index with <code>list[offset] = ...</code>, use this syntax:
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = [None] * 10
l = [None] * 5
l[2] = 'A' # [None, None, 2, None, None]
</syntaxhighlight>
</syntaxhighlight>


Line 202: Line 203:
l1.extend(l2)
l1.extend(l2)
print(l1) # will display [1, 2, 3, 10, 20]
print(l1) # will display [1, 2, 3, 10, 20]
</syntaxhighlight>
Note that the argument of the <code>extend()</code> function may not be <code>None</code>. If that happens, we get:
<syntaxhighlight lang='text'>
TypeError: 'NoneType' object is not iterable
</syntaxhighlight>
</syntaxhighlight>
The <code>extend()</code> function is equivalent with the <code>+=</code> operator:
The <code>extend()</code> function is equivalent with the <code>+=</code> operator:
Line 210: Line 215:
print(l1) # will display [1, 2, 3, 10, 20]
print(l1) # will display [1, 2, 3, 10, 20]
</syntaxhighlight>
</syntaxhighlight>
===<span id='insert'></span>Insert an Element in the Middle of a List===
===<span id='insert'></span>Insert an Element in the Middle of a List===
<code>insert(offset, element)</code> inserts an element in the middle of the list. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.
<code>insert(offset, element)</code> inserts an element in the middle of the list. ⚠️ <code>insert()</code> will increase the list length. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l1 = [1, 2, 3]
l1 = [1, 2, 3]
Line 230: Line 236:
del l[-1] # the list is now [2]
del l[-1] # the list is now [2]
</syntaxhighlight>
</syntaxhighlight>
===Delete an Element by its Value===
===Remove (Delete) an Element by its Value===
<code>remove()</code> deletes an element from a list based on its value. If more than one elements have the same value, only the first one is removed.
<code>remove()</code> deletes an element from a list based on its value and compacts the list.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
l.remove('b')
assert l == ['a', 'c']
</syntaxhighlight>
If more than one elements have the same value, only the first one is removed:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'b', 'd']
l.remove('b')
assert l == ['a', 'c', 'b', 'd']
</syntaxhighlight>
If the element is not present, the method raises <code>ValueError</code>:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
try:
  l.remove('d')
except ValueError:
  pass
assert l == ['a', 'b', 'c']
</syntaxhighlight>
 
===Return and Remove an Element with <tt>pop()</tt>===
===Return and Remove an Element with <tt>pop()</tt>===
An element identified by offset can be returned and deleted from the list. Positives and negative offsets work.
An element identified by offset can be returned and deleted from the list. Positives and negative offsets work.
Line 251: Line 278:


Note that the list can be iterated in reverse order with the built-in <code>[[#Iterate_over_a_List_in_Reversed_Order|reversed()]]</code>.
Note that the list can be iterated in reverse order with the built-in <code>[[#Iterate_over_a_List_in_Reversed_Order|reversed()]]</code>.
===Remove an Element while Iterating===
Evaluate the list by index, going backwards. Note that if we're storing the processed and deleted elements into secondary storage, at the end it must be revered to preserve the original order.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'a', 'd']
for i in range(len(l)-1, -1, -1):
    if l[i] == 'a':
        del l[i]
assert l == ['b', 'c', 'd']
</syntaxhighlight>


==Delete All Elements==
==Delete All Elements==


=Copy a List=
=Copy a List=
<syntaxhighlight lang='py'>
lst = [2, 3, 5]
lst_copy = lst.copy()
</syntaxhighlight>
=Printing Lists=
=Printing Lists=
<font color=darkkhaki>If <code>print()</code> is called on list that contain custom class instances, <code>__str()__</code> does not seem to be called on instances.</font>
<font color=darkkhaki>If <code>print()</code> is called on list that contain custom class instances, <code>__str()__</code> does not seem to be called on instances.</font>
Line 284: Line 328:


==<span id='Sorting'></span>Sort==
==<span id='Sorting'></span>Sort==
There are two methods that can be used to sort lists: <code>list.sort()</code> and <code>sorted()</code>. The <code>sort()</code> sorts the list in-place, while <code>sorted()</code> creates a copy of the list and leaves the argument unmodified:
There are two methods that can be used to sort lists: <code>list.sort()</code> and <code>sorted()</code>. The <code>sort()</code> sorts the list in-place, while <code>[[Python_Built-In_Function_sorted()#Overview|sorted()]]</code> creates a copy of the list and leaves the argument unmodified:
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = ['c', 'b', 'a']
l = ['c', 'b', 'a']
Line 297: Line 341:
assert ['a', 'b', 'c'] == l2
assert ['a', 'b', 'c'] == l2
</syntaxhighlight>
</syntaxhighlight>
For a discussion on how elements are compared, see: {{Internal|Python_Built-In_Function_sorted()#Comparing_Elements|<tt>sorted()</tt> &#124; Comparing Elements}}


==Iterate over a List in Reversed Order==
==Iterate over a List in Reversed Order==
Line 318: Line 363:
for i, e in enumerate(l):
for i, e in enumerate(l):
     print(f'index: {i}, element: {e}')
     print(f'index: {i}, element: {e}')
</syntaxhighlight>
=Subclass a List=
<syntaxhighlight lang='py'>
class MockList(list):
    # noinspection PyUnusedLocal
    def __init__(self, *args, **kwargs):
        super().__init__()
        milestone = kwargs.get('milestone')
        if milestone is None:
            self._storage = test_issues.copy()
        elif milestone == '*':
            self._storage = [get_mock_issue(1, 'issue 1')]
        elif milestone == 'none':
            self._storage = [get_mock_issue(2, 'issue 2')]
        elif isinstance(milestone, Mock):
            self._storage = [get_mock_issue(3, 'issue 3')]
        else:
            raise ValueError(f'unexpected milestone: {milestone}')
    def __str__(self):
        return str(self._storage)
    def __len__(self, *args, **kwargs):
        return len(self._storage)
    def __getitem__(self, y):
        return self._storage.__getitem__(y)
    def __iter__(self, *args, **kwargs):
        return self._storage.__iter__()
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 01:32, 26 April 2023

Internal

TODO

  • TO PROCESS PyOOP "Lists", "Sorting lists"

Overview

A list is a mutable sequence type that contains zero or more elements and whose elements can be of the same type or different types. The elements of a list are ordered. As mentioned, the list is mutable, in that a list can be changed in-place, new elements can be added to it, and existing elements can be overwritten. Unlike a set, a list can contain the same element multiple times, a list element does not need to be unique in the list.

List type()

The function type() applied to a list returns: <class 'list'>

To check whether an instance is a list:

i = ...
if type(i) is list:
  ...

For list subclasses:

i = ...
if isinstance(i, list):
  ...

List Comparison

Two different list instances that contain the same values in the same order are considered equal:

l = ['a', 'b', 'c']
l2 = ['a', 'b', 'c']
assert l == l2 # passes

Create a List

A list can be created with the [] syntax, with the list() functions and with list comprehensions.

Create a List with []

A list can be created specifying the list elements, separate them by comma and enclose them in square brackets.

empty_list = []
some_list = ['A', 'B', 'C']
some_other_list = ['A', 2, 3.0, ['B', 4]]

Create a List or Convert other Data Type to a List with list()

An empty list can be created with the list() function:

empty_list = list()

The list() function converts the data types to lists. list() applied to a list creates a copy of that list. The data types that can be converted are:

String to List

s = 'abc'
l = list(s)
assert l == ['a', 'b', 'c']

Tuple to List

t = ('a', 'b', 'c')
l = list(t)
assert l == ['a' ,'b', 'c']

Create a List of Specific Size

To create a list of specific size, so arbitrary elements can be set in place at a specific index with list[offset] = ..., use this syntax:

l = [None] * 5
l[2] = 'A' # [None, None, 2, None, None]

Create a Copy of a List

l = ['a', 'b', 'c']
l2 = l.copy()

l[0] = 'x'
assert 'x' == l[0]
assert 'a' == l2[0]

Access a List

Test for Empty List

Test for Existence of an Element in List

A Python idiomatic way to test whether a value is in the list is using in:

l = ['a', 'b', 'c', 'b', 'd']
if 'a' in l:
  print("'a' found")
else:
  print("'a' NOT found")
if 'x' in l:
  print("'x' found")
else:
  print("'x' NOT found")

The offset of an element with a certain value can be returned by calling index().

l = ['a', 'b', 'c', 'b', 'd']
assert 1 == l.index('b')

If the element exists in list, the index() returns the offset of the first value in the list, in case the value exists more than once. If the value does not exist, the method will throw ValueError: '...' is not in list.

Access an Element in List

The element of a list can be accessed using the [<offset>] syntax. The offset is zero-based, and it can be positive or negative.

l = ['a', 'b', 'c']
print(l[0])

Negative indices count backward from the end, the last element is identified with a -1 index. Think about it as index = len(list) - negative-index.

l = ['a', 'b', 'c']
assert 'c' == l[-1]
assert 'b' == l[-2]

⚠️ In case of both positive and negative indices, the offset should be valid. If the indices fall outside of the list's bounds, IndexError: list index out of range exception is thrown.

Length of a List

The number of elements is given by the len() function:

l = ['a', 'b', 'c']
assert 3 == len(l)

Count Occurrences of a Value with count()

l = ['a', 'b', 'c', 'a']
assert 2 == l.count('a')

Iterate over a List

Python Language | Loops and Iterations

Slices

A sub-sequence of a list can be extracted with a slice. The slice [<start-index>:<end-index>:<step>] specified the index of the last element, and the index of the first element not included in slice, and the step. The step is optional, the default value is 1.

l = ['a', 'b', 'c', 'd', 'e', 'f']
assert ['a', 'b', 'c', 'd', 'e', 'f'] == l[:] # starts from the beginning and ends after the end of the list
assert ['c', 'd'] == l[2:4]
assert ['c'] == l[2:4:2]

The step can be negative, which means the slice starts at the end and goes from right to left.

l = ['a', 'b', 'c', 'd', 'e', 'f']
assert ['f', 'e', 'd', 'c', 'b', 'a'] == l[::-1]

[:] creates a copy of the list.

l = ['a', 'b', 'c']
l2 = l[:]
l2[0] = 'x'
assert ['a', 'b', 'c'] == l
assert ['x', 'b', 'c'] == l2

Remove the last element of the list:

l = ['a', 'b', 'c']
l2 = l[:-1]
assert ['a', 'b'] == l2

Extract Elements from the Tail of the List Starting with a Certain Index

l = [1, 2, 3]
assert l[0:] == [1, 2, 3]
assert l[1:] == [2, 3]
assert l[2:]== [3]
assert l[3:] == [] # empty list
assert l[4:] == [] # empty list

Extract Elements from the Head of the List Counting from the Tail

TODO

Modify a List

Modify Individual Elements

Modify an Element Identified by [offset]

An element of a list can be modified using the [<offset>] syntax. The offset is zero-based, and it can be positive or negative, as described in Access an Element in List.

l = ['a', 'b', 'c']
l[1] = 'd'
print(l[1])

Append an Element

The traditional way of adding items to a list is to append() them one by one to the end of the list. The invocation increases the length of the list.

l = [1, 2, 3]
l.append(10)
print(l) # will display [1, 2, 3, 10]

append() adds the argument to the end of the list, as one element, even if it's another list. To extend the list by adding the elements individually, use extend() or +=.

⚠️ Do not use append() to append the content of another list. append() works only for individual elements, if used with a list, it appends the list itself, not its elements. Use extent() instead.

Append a List

A list can be extended with another list with the extend() function:

l1 = [1, 2, 3]
l2 = [10, 20]
l1.extend(l2)
print(l1) # will display [1, 2, 3, 10, 20]

Note that the argument of the extend() function may not be None. If that happens, we get:

TypeError: 'NoneType' object is not iterable

The extend() function is equivalent with the += operator:

l1 = [1, 2, 3]
l2 = [10, 20]
l1 += l2
print(l1) # will display [1, 2, 3, 10, 20]

Insert an Element in the Middle of a List

insert(offset, element) inserts an element in the middle of the list. ⚠️ insert() will increase the list length. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.

l1 = [1, 2, 3]
l1.insert(1, 10)
print(l1) # will display [1, 10, 2, 3]
l1.insert(1000, 20)
print(l1) # will display [1, 10, 2, 3, 20]
l1.insert(-1000, 40)
print(l1) # will display [40, 1, 10, 2, 3, 20]

Delete an Element by Offset

To delete an element by offset use del list_name[<offset>]. The offset can be positive or negative. Using -1 deletes the last element from the list.

l = [1, 2, 3]
del l[0] # the list is now [2, 3]
del l[-1] # the list is now [2]

Remove (Delete) an Element by its Value

remove() deletes an element from a list based on its value and compacts the list.

l = ['a', 'b', 'c']
l.remove('b')
assert l == ['a', 'c']

If more than one elements have the same value, only the first one is removed:

l = ['a', 'b', 'c', 'b', 'd']
l.remove('b')
assert l == ['a', 'c', 'b', 'd']

If the element is not present, the method raises ValueError:

l = ['a', 'b', 'c']
try:
  l.remove('d')
except ValueError:
  pass
assert l == ['a', 'b', 'c']

Return and Remove an Element with pop()

An element identified by offset can be returned and deleted from the list. Positives and negative offsets work.

l = [1, 2, 3]
print(l.pop(1)) # displays 2
print(l) # displays [1, 3]

pop() without argument implies -1: the last element of the list will be returned and deleted.

Reverse a List In-place

A list can be reversed in-place with reverse().

l = [1, 2, 3]
l.reverse()
print(l) # displays [3, 2, 1]

⚠️ reverse() returns None, not a list! The reversal is done in place. The fact that the method does not return anything is counterintuitive, it cannot use as part of a flow syntax.

Note that the list can be iterated in reverse order with the built-in reversed().

Remove an Element while Iterating

Evaluate the list by index, going backwards. Note that if we're storing the processed and deleted elements into secondary storage, at the end it must be revered to preserve the original order.

l = ['a', 'b', 'c', 'a', 'd']

for i in range(len(l)-1, -1, -1):
    if l[i] == 'a':
        del l[i]

assert l == ['b', 'c', 'd']

Delete All Elements

Copy a List

lst = [2, 3, 5]
lst_copy = lst.copy()

Printing Lists

If print() is called on list that contain custom class instances, __str()__ does not seem to be called on instances.

Multi-Dimensional Lists

m = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
print(m[2][1]) # prints 8

List Processing

split(), join()

A string can be converted into a list containing tokens delimited by separators in the string using the split() function. split() is a string function. The elements of the newly created list are strings.

s='a b c'
l = s.split(' ') # l is ['a', 'b', 'c']

If two separators occur in succession in the string, the list contains an empty string:

s='a,,b,c'
l = s.split(',') # l is ['a', '', 'b', 'c']

The string can then be put back together with join(). Note that join() is a string method, not a list method, so it should be applied to the separator string. The elements of the list must be strings, otherwise an exception is thrown: TypeError: sequence item 0: expected str instance, int found.

l = ['a', 'b', 'c', 'd']
s = ', '.join(l)
print(s) # will display a, b, c, d

join() being a string method, can be used with other iterable types like tuple or set.

Sort

There are two methods that can be used to sort lists: list.sort() and sorted(). The sort() sorts the list in-place, while sorted() creates a copy of the list and leaves the argument unmodified:

l = ['c', 'b', 'a']
l.sort()
assert ['a', 'b', 'c'] == l

The default sort order is ascending, but if the sort(reverse=True) is invoked with reverse=True, the order will be switched to descending.

l = ['c', 'b', 'a']
l2 = sorted(l)
assert ['c', 'b', 'a'] == l
assert ['a', 'b', 'c'] == l2

For a discussion on how elements are compared, see:

sorted() | Comparing Elements

Iterate over a List in Reversed Order

TO PROCESS PyOOP "Reversed"

reversed() built-in can be used to iterate over a list in reversed order:

l = ['a', 'b', 'c']
for i in reversed(l):
  ...

The list is left unchanged. Note that a list can be revered in-place with reverse()

Access the Index and the Element at the Same Time with enumerate()

TO PROCESS PyOOP "Enumerate"

The enumerate() built-in function gives access to the elements of the list and their index at the same time.

l = ['a', 'b', 'c']
for i, e in enumerate(l):
    print(f'index: {i}, element: {e}')

Subclass a List

class MockList(list):
    # noinspection PyUnusedLocal
    def __init__(self, *args, **kwargs):
        super().__init__()
        milestone = kwargs.get('milestone')
        if milestone is None:
            self._storage = test_issues.copy()
        elif milestone == '*':
            self._storage = [get_mock_issue(1, 'issue 1')]
        elif milestone == 'none':
            self._storage = [get_mock_issue(2, 'issue 2')]
        elif isinstance(milestone, Mock):
            self._storage = [get_mock_issue(3, 'issue 3')]
        else:
            raise ValueError(f'unexpected milestone: {milestone}')

    def __str__(self):
        return str(self._storage)

    def __len__(self, *args, **kwargs):
        return len(self._storage)

    def __getitem__(self, y):
        return self._storage.__getitem__(y)

    def __iter__(self, *args, **kwargs):
        return self._storage.__iter__()