Chapter 3

TUPLES

Tuples are immutable. Doesnt matter if you turn a mutable object into tuple. Its still immutable

You can create tuples like listing

tup = (5,6,7,(8,9,10),'string')

And you can call any item from tuple with a bracket and number

tup[3]

Out: (8, 9, 10)

You can turn anyting into tuple. with a simple tuple function

tup = tuple('string')
tup

Out: (‘s’, ‘t’, ‘r’, ‘i’, ‘n’, ‘g’)

Unpacking Tuples

IF you assign variables as much as len of tuple you can assign each item to a variable.

tup = (1,2,3,(4,5))
a,b,c,d = tup
d

Out: a=1 b=2 c=3 a=4 b=5 c=6 a=7 b=8 c=9

Also you can pluck a few elements from the beginning of a tuple. with a special syntax; rest. Rest bit interchangable. you can use others as well

values = 1,2,3,4,5
a,b,*rest = values
a,b,rest

Out: (1, 2, [3, 4, 5])

LISTS

In contrast with tuples lists are variable length and their contents can be modified. Lists are mutable. You define them by using [] square brackets.

a_list = [1,2,3]
for item in a_list:
    print(item)

Out: 1 2 3

The list built-in function is frequently used in data processing as a way to materialize an iterator or generater expression.

gen = range(10)
gen

Out: range(0, 10)

list(gen)

Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

There are functions built in list. Such as:
.append(add an element at the end of list.),
.insert(insert an element at a specific location),
.pop(removes and returns an element at a particular index),
.remove(takes the value and search it in list and removes first such value) \

gen_list = list(gen)
gen_list.append(10)#add 10 to end of the list
gen_list

Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

gen_list.insert(3,1)#add 1 to 3rd index
gen_list

Out: [0, 1, 2, 1, 3, 4, 5, 6, 7, 8, 10]

gen_list.pop(3)#removes 4th element
gen_list

Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

gen_list.remove(9)#removes the 9
gen_list

Out: [0, 1, 2, 3, 4, 5, 6, 7, 8, 10]

You can sort a list in place by calling sort() function.

Slicing

seq = [7,2,3,7,5,6,0,1]
seq[1:5]#return from starting index 1 till but not including 5

Out: [2, 3, 7, 5]

seq[3:5] = [6,3]#Change 3rd and 4th item to 6,3
seq

Out: [7, 2, 3, 6, 3, 6, 0, 1]

seq[:3]#start from beginning to 3rd item

Out: [7, 2, 3]

seq[3:]#start from 3rd item to end

Out: [6, 3, 6, 0, 1]

seq[-4:]#start from 4th item from the end and list it till end

Out: [3, 6, 0, 1]

DICTIONARY

my_dict = {'a':'some value', 'b': [1,2,3,4]}
my_dict['c'] = 'an integer' #add new element to dict.
my_dict['c']#list the value of key('c')

Out: ‘an integer’

'b' in my_dict#you can ask if a key exist in my_dict

Out: True

my_dict.pop('c')#pops an item
my_dict

Out: {‘a’: ‘some value’, ‘b’: [1, 2, 3, 4]}

list(my_dict.keys())

Out: [‘a’, ‘b’]

list(my_dict.values())

Out: [‘some value’, [1, 2, 3, 4]]

list(my_dict.items())

Out: [(‘a’, ‘some value’), (‘b’, [1, 2, 3, 4])]

my_dict_2 = {1:2,2:3,3:4}
my_dict.update(my_dict_2)#merges two dictionary together
my_dict

Out: {‘a’: ‘some value’, ‘b’: [1, 2, 3, 4], 1: 2, 2: 3, 3: 4}

key_list = ['a','b','c','d','e']#list of keys
value_list = [1,2,3,4,5]#list of values
mapping = {}#empty dictionary
for key, value in zip(key_list, value_list):
    mapping[key] = value
mapping

Out: {‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}

tuples = zip(range(5), reversed(range(5)))#a dictionary is a combination of two tuples
tuples

Out: <zip at 0x10cefd7c0>

mappings = dict(tuples)
mappings

Out: {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}

Set Default Dictionary

You could imagine categorizing a list of words by their first letter as a dictionary of lists.

words = ["apple", "bat", "bar", "atom", "book"]
by_letter = {}

for word in words:
    letter = word[0]
    if letter not in by_letter:
        by_letter[letter] = [word]
    else:
        by_letter[letter].append(word)

by_letter

Out: {‘a’: [‘apple’, ‘atom’], ‘b’: [‘bat’, ‘bar’, ‘book’]}

The setdefault dictionary method can be used to simplify this workflow. The preceding for loop can be rewritten as:

by_letter = {} #lets empty dict.

for word in words:
    letter = word[0]
    by_letter.setdefault(letter,[]).append(word)#its basically setting if key exist enters if else pass and append word to the list.
                                                #this way every key will be added only once.
by_letter

Out: {‘a’: [‘apple’, ‘atom’], ‘b’: [‘bat’, ‘bar’, ‘book’]}

The built-in collections module has a useful class, defaultdict, which makes this even easier. To create one, you pass a type or function for generating the default vallue for each slot in the dictionary.

from collections import defaultdict
by_letter = defaultdict(list)

for word in words:
    by_letter[word[0]].append(word)

by_letter

Out: defaultdict(list, {‘a’: [‘apple’, ‘atom’], ‘b’: [‘bat’, ‘bar’, ‘book’]})

SET

A set is an unordered collection of unique elements.

set([2,2,2,1,3,3])

Out: {1, 2, 3}

{2,2,2,1,3,3}

Out: {1, 2, 3}

a = {1,2,3,4,5}
b = {3,4,5,6,7,8}
a.union(b)

Out: {1, 2, 3, 4, 5, 6, 7, 8}

a|b

Out: {1, 2, 3, 4, 5, 6, 7, 8}

a.intersection(b)
a&b

Out: {3, 4, 5}

a.clear()#Reset set to an empty state discarding all of its elements
a.add('x')#Add element x to set a

a = {1,2,3,4,5,'x'}
a.remove('x')#Remove element x from set a
a.pop()#remove an arbitrary element from seet a raising keyerror if the set is empty

a.union(b)#Combines set a and b with unique elements
a.update(b)#Set the contents of a to be the union of elements in a and b

a.intersection(b)#All of the elements that is both in a and in b
a.intersection_update(b)#Set the contents of a to be the intersection of the elements in a and b

a.difference(b)#The elements in a that are not in b
a.difference_update(b)#set a to the elements in a that are not in b
a.symmetric_difference(b)#all of the elements in either a or b but not both
a.symmetric_difference_update(b)#set a to contain the elements in either a or b but not both

a.issubset(b)#True if the elements of a are all contained in b
a.issuperset(b)#true if the elements of b are all contained in a
a.isdisjoint(b)#true if a and b have no elements in common.

enumerate

words = ['apple', 'banana', 'orange', 'pear']

for i, word in enumerate(words):
    print(word)
    print(i)

Out: apple 0 banana 1 orange 2 pear 3

List, Set and Dictionary Comprehensions

List Comprehensions:

strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
result = []
for string in strings:
    if len(string)>2:
        result.append(string)
result
#This is the long way we can instead do it like the below

Out: [‘bat’, ‘car’, ‘dove’, ‘python’]

result = [string for string in strings if len(string)>2]
result

Out: [‘bat’, ‘car’, ‘dove’, ‘python’]

Dict and set comprehensions are similar:
dict_comp = {key-expr: value-expr for value in collection if condition}
set_comp = {expr for value in collection if condition}

FUNCTIONS

def short_function(x):
  return x*2

Instead you can write it like this:

equiv_anon = lambda x: x*2
equiv_anon(5)

Out: 10