Collections in python

Definition of iterable and sequence objects

What is an iterable object?

An object capable of returning its members one at a time.
Examples of iterables
– all sequence types (such as list, str, and tuple)
– some non-sequence types like dict, file objects
– objects of any classes you define with an __iter__() method or with a __getitem__() method that implements sequence semantics.

What is a sequence object?

An iterable which supports efficient element access using integer indices via the __getitem__() special method and defines a __len__() method that returns the length of the sequence.
Examples of sequences:
– Some built-in sequence types are list, str, tuple, and bytes.

beware: dict implements the 2 functions but is considered a mapping rather than a sequence.

Sequences

Common types

There are 4 basic sequence types: lists, tuples, str and range objects.
Additional sequence types tailored for processing of binary data and text strings are described in dedicated sections.

Command sequence operations

__getitem__() : efficient element access using integer indices 
– __len__() : method that returns the length of the sequence.
The collections.abc.Sequence abstract base class defines a much richer interface that goes beyond just __getitem__() and __len__(), adding count(), index(), __contains__(), and __reversed__().


Common functions to sequences :

x in s : True if an item of s is equal to x, else False

x not in s : False if an item of s is equal to x, else True

s + t : concatenation of s and t

s * n or n * s : equivalent to adding s to itself n times

s[i] : ith item of s, origin 0

s[i:j] : slice of s from i to j

s[i:j:k] : slice of s from i to j with step k

len(s) : length of s

min(s) : smallest item of s

max(s) : largest item of s

s.index(x[, i[, j]]) : index of the first occurrence of x in s (at or after index i and before index j)

s.count(x) : total number of occurrences of x in s

concrete example of basic functions of sequences
string example:

    def test_string_sequence_functions(self):
        foo: str = 'I am a good person'
        # in
        self.assertTrue('am' in foo)
        #  not in
        self.assertTrue('Am' not in foo)
        # +
        self.assertEqual('I am a good person and you?', foo + ' and you?')
        # *
        self.assertEqual('I am a good personI am a good personI am a good person', foo * 3)
        # access by index
        self.assertEqual('I', foo[0])
        self.assertEqual('g', foo[7])
        self.assertEqual('o', foo[8])
        self.assertEqual('o', foo[9])
        # access form the last elements
        self.assertEqual('n', foo[-1])
        self.assertEqual('o', foo[-2])
 
        # slice
        self.assertEqual('am', foo[2:4])
        self.assertEqual('I am a good ', foo[:12])
        self.assertEqual('person', foo[12:])
 
        # length
        self.assertEqual(18, len(foo))
 
        # min and max
        self.assertEqual(' ', min(foo))
        self.assertEqual('s', max(foo))
 
        # index of the first occurrence of x in s
        self.assertEqual(2, foo.index('a'))
        # index of the first occurrence of x in s by starting by the index 3
        self.assertEqual(5, foo.index('a', 3))
 
        # total number of occurrences of x in s
        self.assertEqual(1, foo.count('I'))
        self.assertEqual(3, foo.count('o'))
        self.assertEqual(0, foo.count('z'))

list example:

    def test_list_sequence_functions(self):
        foo: List[int] = [1, 5, 10, 5, 5, 0]
        # in
        self.assertTrue(1 in foo)
        self.assertTrue(5 in foo)
        #  not in
        self.assertTrue(2 not in foo)
        # +
        self.assertEqual([1, 5, 10, 5, 5, 0, 9, 88], foo + [9, 88])
        # *
        self.assertEqual([1, 5, 10, 5, 5, 0, 1, 5, 10, 5, 5, 0], foo * 2)
        # access by index
        self.assertEqual(1, foo[0])
        self.assertEqual(5, foo[1])
        self.assertEqual(10, foo[2])
        # access form the last elements
        self.assertEqual(0, foo[-1])
        self.assertEqual(5, foo[-2])
 
        # slice
        self.assertEqual([10, 5], foo[2:4])
        self.assertEqual([1, 5, 10, 5], foo[:4])
        self.assertEqual([10, 5, 5, 0], foo[2:])
 
        # length
        self.assertEqual(6, len(foo))
 
        # min and max
        self.assertEqual(0, min(foo))
        self.assertEqual(10, max(foo))
 
        # index of the first occurrence of x in s
        self.assertEqual(1, foo.index(5))
        # index of the first occurrence of x in s by starting by the index 3
        self.assertEqual(3, foo.index(5, 2))
 
        # total number of occurrences of x in s
        self.assertEqual(1, foo.count(1))
        self.assertEqual(3, foo.count(5))
        self.assertEqual(0, foo.count(9))

tuple basic example:

    def test_tuple_sequence_functions(self):
        foo: tuple[int, str, str] = (1, 'David', 'Doe')
        # in
        self.assertTrue(1 in foo)
        self.assertTrue('David' in foo)
        self.assertTrue('Doe' in foo)
        #  not in
        self.assertTrue(2 not in foo)
        # +
        self.assertEqual((1, 'David', 'Doe', 'lion', 'tiger'), foo + ('lion', 'tiger'))
        # *
        self.assertEqual((1, 'David', 'Doe', 1, 'David', 'Doe'), foo * 2)
        # access by index
        self.assertEqual(1, foo[0])
        self.assertEqual('David', foo[1])
        self.assertEqual('Doe', foo[2])
        # access form the last elements
        self.assertEqual('Doe', foo[-1])
        self.assertEqual('David', foo[-2])
 
        # slice
        self.assertEqual((1, 'David'), foo[0:2])
        self.assertEqual((1, 'David', 'Doe'), foo[:3])
        self.assertEqual(('David', 'Doe'), foo[1:])
 
        # length
        self.assertEqual(3, len(foo))
 
        # min and max
        # the aggregate function minimum and maximum cannot work with different types
        # self.assertEqual(0, min(foo))
        # self.assertEqual(10, max(foo))
 
        # index of the first occurrence of x in s
        self.assertEqual(1, foo.index('David'))
        # index of the first occurrence of x in s by starting by the index 3
        self.assertEqual(1, foo.index('David', 1))
 
        # total number of occurrences of x in s
        self.assertEqual(1, foo.count(1))
        self.assertEqual(1, foo.count('Doe'))
        self.assertEqual(0, foo.count(9))

tuple imutability example

from typing import Tuple
 
 
class Foo:
 
    def __init__(self, text) -> None:
        self.text = text
 
    def __repr__(self) -> str:
        return f'Foo: text={self.text}'
 
 
foo_hello = Foo('hello')
foo_boy = Foo('boy')
t: Tuple[Foo, Foo] = (foo_hello, foo_boy)
print(f'id={id(t)}, t={t}')
# id=3055929302144, t=(Foo: text=hello, Foo: text=boy)
 
foo_boy.text = 'girl'
print(f'id={id(t)}, t={t}')
# id=3055929302144, t=(Foo: text=hello, Foo: text=girl)
t += t
print(f'id={id(t)}, t={t}')
# id=3055928752896, t=(Foo: text=hello, Foo: text=girl, Foo: text=hello, Foo: text=girl)

Output:

id=2052380007168, t=(Foo: text=hello, Foo: text=boy)
id=2052380007168, t=(Foo: text=hello, Foo: text=girl)
id=2052379458144, t=(Foo: text=hello, Foo: text=girl, Foo: text=hello, Foo: text=girl)

list() and set() built-in functions

Overview

These two functions have a close behavior:
– They create a list object or a set object.
– Two ways to use them: either we provide no parameter to create an empty collection or we specify an iterable as parameter and it creates a collection with elements contained in the iterable parameter.

Examples

from typing import List
from typing import Set
 
l: List[str] = list('gin')
print(f'l={l}')
# l=['g', 'i', 'n']
 
s: Set[str] = set('gin')
print(f's={s}')
# s={'n', 'i', 'g'}
 
s: Set[str] = set(['gin', 'john', 'gin'])
print(f's={s}')
# s={'john', 'gin'}
 
l: List[str] = list({'gin', 'john'})
print(f'l={l}')
# l=['john', 'gin']
 
s: Set[str] = {'gin', 'john'}
print(f's={s}')
# s={'john', 'gin'}
 
s: Set[str] = {'gin', 'john', 'gin'}
print(f's={s}')
# s={'john', 'gin'}
 
s: Set[str] = set()
s.add('gin')
print(f's={s}')
# s={'gin'}
 
l: List[str] = list()
l.append('gin')
print(f'l={l}')
# l=['gin']

Dictionary

What is it ?

Very close of a Map (in Java/C# for example), a dictionary is a set of key:value elements, whereb keys are unique.

Initialize a dictionary

# empty dic
empty_dic = {}
 
# dic with st key and number value
dic = {'jack': 1234, 'john': 4567}
 
# dic with number key and str value
dic = {1234: 'jack', 4567: 'john'}
 
# dic with number key and list value
dic = {1234: ['jack', 'jackie'], 4567: ['john', 'johnny']}

Basic operations on dictionary

– get value for a key
– query key contained in
– query key not contained in
– add or update an element
– delete an element
– get list of keys, sorted by insertion order
– get list of keys, sorted asc

pleasures_by_food = {
        'potatoes': 'very good',
        'chicken': 'good',
}
 
# get value for 'potatoes' key
print('potatoes pleasure = ', pleasures_by_food['potatoes'])
 
# query key contained in
print('does it contain chicken ?', 'chicken' in pleasures_by_food)
 
# query key not contained in
print('does it not contain chicken ?', 'chicken' not in pleasures_by_food)
 
# add the cheese element
pleasures_by_food['cheese'] = 'interesting'
 
# update the potatoes element
print('update the potatoes element')
pleasures_by_food['potatoes'] = 'not bad'
print(f'pleasures_by_food={pleasures_by_food}')
 
# del the cheese element
print('Remove cheese key')
# del pleasures_by_food['cheese']
# alternative to delete
pop = pleasures_by_food.pop('cheese')
print(f'pop={pop}')
# alternative to delete with default value if key does not exist
pop = pleasures_by_food.pop('cheese', 'unknown')
print(f'pop={pop}')
 
# get a list of keys sorted by insertion order
print(list(pleasures_by_food))
 
# get a list of keys sorted by ascending order
print('Sort dictionary')
print(sorted(pleasures_by_food)

Merging collections

Merging dictionaries

Updating an existing dictionary

update(other)
Update the dictionary with the key/value pairs from other, overwriting existing keys.
Return None.
update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two).

New in version 3.9 (| As union operator):
d |= other
Update the dictionary d with keys and values from other, which may be either a mapping or an iterable of key/value pairs. The values of other take priority when d and other share keys.

Creating a new dictionary

New in version 3.9 (| As union operator):
d | other:
Create a new dictionary with the merged keys and values of d and other, which must both be dictionaries. The values of other take priority when d and other share keys.

Examples

knights = {
        'gallahad': 'the pure',
        'robin': 'the brave',
        'nobody': 'knights'
}
queens = {
        'diana': 'the love',
        'helena': 'the mother',
        'nobody': 'queen'
}
 
# Creating a new dictionary
print('\nCreating a new dictionary')
knights_queens_new_object = knights | queens
print(f'id(knights)={id(knights)}')
print(f'id(queens)={id(queens)}')
print(f'id(knights_queens_new_object)={id(knights_queens_new_object)}')
print(f'knights_queens_new_object={knights_queens_new_object}')
 
# updating a dictionary
special_queens = {
        'super': 'woman',
        'special': 'mommy',
}
print('\nUpdating a dictionary')
knights.update(special_queens)
print(f'id(knights)={id(knights)}')
print(f'id(special_queens)={id(special_queens)}')
print(f'knights={knights}'

Output:

Creating a new dictionary
id(knights)=140652742766976
id(queens)=140652742767168
id(knights_queens_new_object)=140652742767232
knights_queens_new_object={'gallahad': 'the pure', 'robin': 'the brave', 'nobody': 'queen', 'diana': 'the love', 'helena': 'the mother'}
 
Updating a dictionary
id(knights)=140652742766976
id(special_queens)=140652741891328
knights={'gallahad': 'the pure', 'robin': 'the brave', 'nobody': 'knights', 'super': 'woman', 'special': 'mommy'}

Merging lists

Updating an existing list

list.extend(iterable)
Extend the list by appending all the items from the iterable.
Equivalent to a[len(a):] = iterable.
As alternative, we can also use the += operator.

Creating a new list

We use the + operator.

Examples:

first_array = [1, 3, 5]
second_array = [6, 3, 8]
# Creating a new list
print('\nCreating a new list')
first_array_second_array_new_object = first_array + second_array
print(f'id(first_array)={id(first_array)}')
print(f'id(second_array)={id(second_array)}')
print(f'id(first_array_second_array_new_object)={id(first_array_second_array_new_object)}')
print(f'first_array_second_array_new_object={first_array_second_array_new_object}')
 
# updating a list
special_second_array = [1, 3, 6]
print('\nUpdating a list')
first_array.extend(special_second_array)
# alternative
# first_array+=special_second_array
print(f'id(first_array)={id(first_array)}')
print(f'id(special_second_array)={id(special_second_array)}')
print(f'first_array={first_array}'

Output:

Creating a new list
id(first_array)=139647775655744
id(second_array)=139647775683648
id(first_array_second_array_new_object)=139647775702400
first_array_second_array_new_object=[1, 3, 5, 6, 3, 8]
 
Updating a list
id(first_array)=139647775655744
id(special_second_array)=139647775702464
first_array=[1, 3, 5, 1, 3, 6]
Ce contenu a été publié dans Non classé. Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *