Data Structures#

1. Lists#

  • What are Lists?

  • Lists Vs Arrays

  • Characterstics of a List

  • How to create a list

  • Access items from a List

  • Editing items in a List

  • Deleting items from a List

  • Operations on Lists

  • Functions on Lists

What are Lists#

List is a data type where you can store multiple items under 1 name. More technically, lists act like dynamic arrays which means you can add more items on the fly.

image.png

  • Why Lists are required in programming?

Characterstics of a List#

  • Ordered

  • Changeble/Mutable

  • Hetrogeneous

  • Can have duplicates

  • are dynamic

  • can be nested

  • items can be accessed

  • can contain any kind of objects in python

L = [1,2,3]
L1 = [3,2,1]

L == L1
False

Creating a List#

# Empty
# print([])
# # 1D -> Homo
# print([1,2,3,4,5])
# # 2D
# print([1,2,3,[4,5]])
# # 3D
# print([[[1,2],[3,4]],[[5,6],[7,8]]])
# # Hetrogenous
# print([1,True,5.6,5+6j,'Hello'])
# # Using Type conversion
print(list('hello'))
['h', 'e', 'l', 'l', 'o']

Accessing Items from a List#

# Indexing
L = [1,2,3,4,5,6]
#positive
# print(L[1])
# # Negative
print(L[-3])
4
# Indexing
L = [1,2,3,[4,5,6]]
#positive
# print(L[3][2])
# Negative
print(L[-1][-2])
5
# Indexing
L = [[[1,2],[3,4]],[[5,6],[7,8]]]
#positive
# print(L[0][1][0])

# Slicing
L = [1,2,3,4,5,6]

print(L[1:3])
[2, 3]

Adding Items to a List#

# append (insert at the end of the list 1 item)
L = [1,2,3,4,5]
L.append('hello')
print(L)
[1, 2, 3, 4, 5, 'hello']
# extend (insert at the end of the list multiple items)
L = [1,2,3,4,5]
L.extend([6,7,8])
print(L)
[1, 2, 3, 4, 5, 6, 7, 8]
L = [1,2,3,4,5]
L.append([6,7,8])
print(L)
[1, 2, 3, 4, 5, [6, 7, 8]]
L = [1,2,3,4,5]
L.extend('True')
print(L)
[1, 2, 3, 4, 5, 'T', 'r', 'u', 'e']
# insert
L = [1,2,3,4,5]
L.insert(5,100)
print(L)
[1, 2, 3, 4, 5, 100]

Editing items in a List#

L = [1,2,3,4,5]

# editing with indexing
# L[1] = 500
# print(L)
# editing with slicing
L[1:4] = [200,300,400]
print(L)
[1, 200, 300, 400, 5]

Deleting items from a List#

# del
L = [1,2,3,4,5]

# indexing
# del L[1]
# print(L)
# slicing
del L[1:3]
print(L)
[1, 4, 5]
# remove
L = [1,2,3,4,5]
L.remove(2)
print(L)
[1, 3, 4, 5]
# pop
L = [1,2,3,4,5]
# L.pop(1) # remove the item at index 0 from the list 
L.pop()  # remove the last item from the list (default is to remove the last item)
print(L)
[1, 2, 3, 4]
# clear
L = [1,2,3,4,5]
L.clear()
print(L)
[]

Operations on Lists#

  • Arithmetic

  • Membership

  • Loop

# Arithmetic (+ ,*)

L1 = [1,2,3,4]
L2 = [5,6,7,8]

# Concatenation/Merge
print(L1 + L2)
[1, 2, 3, 4, 5, 6, 7, 8]
print(L1*3)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
L1 = [1,2,3,4,5]
L2 = [1,2,3,4,[5,6]]

print(5 not in L1)
print([5,6] in L2)
False
True
# Loops
L1 = [1,2,3,4,5]
L2 = [1,2,3,4,[5,6]]
L3 = [[[1,2],[3,4]],[[5,6],[7,8]]]

for i in L3:
  print(i)
[[1, 2], [3, 4]]
[[5, 6], [7, 8]]

List Functions#

# len/min/max/sorted
L = [2,1,5,7,0]

print(len(L))
print(min(L))
print(max(L))
print(sorted(L,reverse=True))
5
0
7
[7, 5, 2, 1, 0]
# count
L = [1,2,1,3,4,1,5]
L.count(2)
1
# index (returns the index of the first occurence)
L = [1,2,1,3,4,1,5]
L.index(3)
3
# reverse
L = [2,1,5,7,0]
# permanently reverses the list
L.reverse()
print(L)
[0, 7, 5, 1, 2]
# sort (vs sorted)
L = [2,1,5,7,0]
print(L)
print(sorted(L))
print(L)
L.sort()
print(L)
[2, 1, 5, 7, 0]
[0, 1, 2, 5, 7]
[2, 1, 5, 7, 0]
[0, 1, 2, 5, 7]
# copy -> shallow
L = [2,1,5,7,0]
print(L)
print(id(L))
L1 = L.copy()
print(L1)
print(id(L1))
[2, 1, 5, 7, 0]
1552892242624
[2, 1, 5, 7, 0]
1552892243392

List Comprehension#

List Comprehension provides a concise way of creating lists.

newlist = [expression for item in iterable if condition == True]image.png

Advantages of List Comprehension

  • More time-efficient and space-efficient than loops.

  • Require fewer lines of code.

  • Transforms iterative statement into a formula.

# Add 1 to 10 numbers to a list
L = []

for i in range(1,11):
  L.append(i)

print(L)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
L = [i for i in range(1,11) if i != 5]
print(L)
[1, 2, 3, 4, 6, 7, 8, 9, 10]
# scalar multiplication on a vector
v = [2,3,4]
s = -3
# [-6,-9,-12]

[s*i for i in v]
[-6, -9, -12]
# Add squares
L = [1,2,3,4,5]

[i**2 for i in L]
[1, 4, 9, 16, 25]

Disadvantages of Python Lists#

  • Slow

  • Risky usage

  • eats up more memory

a = [1,2,3]
b = a.copy()

print(a)
print(b)

a.append(4)
print(a)
print(b)

# lists are mutable
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3]

Tuples#

A tuple in Python is similar to a list. The difference between the two is that we cannot change the elements of a tuple once it is assigned whereas we can change the elements of a list.

In short, a tuple is an immutable list. A tuple can not be changed in any way once it is created.

Characterstics

  • Ordered

  • Unchangeble

  • Allows duplicate

Plan of Learning#

  • Creating a Tuple

  • Accessing items

  • Editing items

  • Adding items

  • Deleting items

  • Operations on Tuples

  • Tuple Functions

Creating Tuples#

# empty
t1 = ()
print(t1)
print(type(t1))
# # create a tuple with a single item
t2 = ('hello',)
print(t2)
print(type(t2))
print(type(t2))
# homogeneous
t3 = (1,2,3,4)
print(t3)
# hetrogeneous
t4 = (1,2.5,True,{2,7},[1,2,3])
print(t4)
# tuple in tuple
t5 = (1,2,3,(4,5))
print(t5)
# using type conversion
t6 = tuple('hello',)
print(t6)
()
<class 'tuple'>
('hello',)
<class 'tuple'>
<class 'tuple'>
(1, 2, 3, 4)
(1, 2.5, True, {2, 7}, [1, 2, 3])
(1, 2, 3, (4, 5))
('h', 'e', 'l', 'l', 'o')

Accessing Items#

  • Indexing

  • Slicing

t3 = (1,2,3,4)
print(t3)
print(t3[0])
print(t3[-1])
(1, 2, 3, 4)
1
4
t5 = (1,2,3,(4,5))
t5[-1][0]
4

Editing items#

print(t3)
t3[0] = 100
# immutable just like strings
(1, 2, 3, 4)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[34], line 2
      1 print(t3)
----> 2 t3[0] = 100
      3 # immutable just like strings

TypeError: 'tuple' object does not support item assignment

Adding items#

print(t3)
# not possible
(1, 2, 3, 4)

Deleting items#

print(t3)
del t3
print(t3)
(1, 2, 3, 4)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[42], line 3
      1 print(t3)
      2 del t3
----> 3 print(t3)

NameError: name 't3' is not defined
print(t5)
del t5[-1]
(1, 2, 3, (4, 5))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[43], line 2
      1 print(t5)
----> 2 del t5[-1]

TypeError: 'tuple' object doesn't support item deletion

Operations on Tuples#

# + and *
t1 = (1,2,3,4)
t2 = (5,6,7,8)

print(t1 + t2)

print(t1*3)

# iteration
for i in t1:
  print(i)
(1, 2, 3, 4, 5, 6, 7, 8)
(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)
1
2
3
4
# membership
1 in t1
True

Tuple Functions#

# len/sum/min/max/sorted
t = (1,2,3,4)
len(t)
sum(t)
min(t)
max(t)
sorted(t,reverse=True)
[4, 3, 2, 1]
# count

t = (1,2,3,4,5)

t.count(5)
1
# index
t.index(5)
4

Difference between Lists and Tuples#

  • Syntax

  • Mutability

  • Speed

  • Memory

  • Built in functionality

  • Error prone

  • Usability

a = [1,2,3]
b = a

a.append(4)
print(a)
print(b)
[1, 2, 3, 4]
[1, 2, 3, 4]
a = (1,2,3)
b = a

a = a + (4,)
print(a)
print(b)
(1, 2, 3, 4)
(1, 2, 3)

Sets#

A set is an unordered collection of items. Every set element is unique (no duplicates) and must be immutable (cannot be changed).

However, a set itself is mutable. We can add or remove items from it.

Sets can also be used to perform mathematical set operations like union, intersection, symmetric difference, etc.

Characterstics:

  • Unordered

  • Mutable

  • No Duplicates

  • Can’t contain mutable data types

Creating Sets#

# empty
s = set()
print(s)
print(type(s))
print(type(s))
# 1D and 2D
s1 = {1,2,3}
print(s1)
# s2 = {1,2,3,{4,5}}
# print(s2)
# homo and hetro
s3 = {1,'hello',4.5,(1,2,3)}
print(s3)
# using type conversion

s4 = set([1,2,3])
print(s4)
# duplicates not allowed
s5 = {1,1,2,2,3,3}
print(s5)
# set can't have mutable items
# s6 = {1,2,[3,4]}
# print(s6)
set()
<class 'set'>
<class 'set'>
{1, 2, 3}
{1, 'hello', (1, 2, 3), 4.5}
{1, 2, 3}
{1, 2, 3}
s1 = {1,2,3}
s2 = {3,2,1}

print(s1 == s2)
True

Accessing Items#

s1 = {1,2,3,4}
s1[0:3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[53], line 2
      1 s1 = {1,2,3,4}
----> 2 s1[0:3]

TypeError: 'set' object is not subscriptable

Editing Items#

s1 = {1,2,3,4}
s1[0] = 100
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[54], line 2
      1 s1 = {1,2,3,4}
----> 2 s1[0] = 100

TypeError: 'set' object does not support item assignment

Adding Items#

S = {1,2,3,4}
# add
S.add(5)
print(S)
# update
S.update([5,6,7])
print(S)
{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5, 6, 7}

Deleting Items#

# del
s = {1,2,3,4,5}
# print(s)
# del s[0]
# print(s)
# discard
# s.discard(2)
# print(s)
# remove
# s.remove(4)
# print(s)
# pop
# s.pop()
# print(s)
# clear
s.clear()
print(s)
set()

Set Operation#

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
# s1 | s2
# Union(|)
# Intersection(&)
# s1 & s2
# # Difference(-)
# s1 - s2
# s2 - s1
# # Symmetric Difference(^)
# s1 ^ s2
# # Membership Test
# 1 not in s1
# # Iteration
for i in s1:
  print(i)
1
2
3
4
5

Set Functions#

# len/sum/min/max/sorted
s = {3,1,4,5,2,7}
len(s)
sum(s)
min(s)
max(s)
sorted(s,reverse=True)
[7, 5, 4, 3, 2, 1]
# union/update
s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}

# s1 | s2
s1.union(s2)

s1.update(s2)
print(s1)
print(s2)
{1, 2, 3, 4, 5, 6, 7, 8}
{4, 5, 6, 7, 8}
# intersection/intersection_update
s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}

s1.intersection(s2)

s1.intersection_update(s2)
print(s1)
print(s2)
{4, 5}
{4, 5, 6, 7, 8}
# difference/difference_update
s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}

s1.difference(s2)

s1.difference_update(s2)
print(s1)
print(s2)
{1, 2, 3}
{4, 5, 6, 7, 8}
# symmetric_difference/symmetric_difference_update
s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}

s1.symmetric_difference(s2)

s1.symmetric_difference_update(s2)
print(s1)
print(s2)
{1, 2, 3, 6, 7, 8}
{4, 5, 6, 7, 8}
s1 = {1,2,3,4,5}
s2 = {3,4,5}

s1.issuperset(s2)
True
# copy
s1 = {1,2,3}
s2 = s1.copy()

print(s1)
print(s2)
{1, 2, 3}
{1, 2, 3}

Set Comprehension#

# examples

{i for i in range(1,11)}
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
# examples
{i**2 for i in range(1,11) if i>5}
{36, 49, 64, 81, 100}

Dictionary#

Dictionary in Python is a collection of keys values, used to store data values like a map, which, unlike other data types which hold only a single value as an element.

In some languages it is known as map or assosiative arrays.

dict = { ā€˜name’ : ā€˜Fahad’ , ā€˜age’ : 20 , ā€˜gender’ : ā€˜male’ }

Characterstics:

  • Mutable

  • Indexing has no meaning

  • keys can’t be duplicated

  • keys can’t be mutable items

Create Dictionary#

# empty dictionary
d = {}
d
# 1D dictionary
d1 = { 'name' : 'Fahad' ,'gender' : 'male' }
d1
# # with mixed keys
d2 = {(1,2,3):1,'hello':'world'}
d2
# 2D dictionary -> JSON
s = {
    'name':'Fahad',
     'college':'lms',
     'sem':4,
     'subjects':{
         'AI':50,
         'maths':67,
         'english':34
     }
}
s
# using sequence and dict function
d4 = dict([('name','Fahad'),('age',32),(3,3)])
d4
# duplicate keys
d5 = {'name':'Fahad','name':'asad'}
d5
# mutable items as keys
d6 = {'name':'Fahad',(1,2,3):2}
print(d6)
{'name': 'Fahad', (1, 2, 3): 2}

Accessing items#

my_dict = {'name': 'Jack', 'age': 26}
# []
# my_dict['name']
# get
# my_dict.get('name')

s['subjects']['maths']
67

Adding key-value pair#

d4 = dict([('name','Fahad'),('age',32),(3,3)])
d4['gender'] = 'male'
d4
d4['weight'] = 72
d4
# update
s['subjects']['AI'] = 75
s
{'name': 'Fahad',
 'college': 'lms',
 'sem': 4,
 'subjects': {'AI': 75, 'maths': 67, 'english': 34}}

Remove key-value pair#

d = {'name': 'Fahad', 'age': 32, 3: 3, 'gender': 'male', 'weight': 72}
# pop
# d.pop('age')
# print(d)
# popitem
# d.popitem()
# print(d)
# del
# del d['name']
# print(d)
# clear
# d.clear()
# print(d)

del s['subjects']['maths']
s
{'name': 'Fahad',
 'college': 'lms',
 'sem': 4,
 'subjects': {'AI': 75, 'english': 34}}

Editing key-value pair#

s['subjects']['AI'] = 80
s
{'name': 'Fahad',
 'college': 'lms',
 'sem': 4,
 'subjects': {'AI': 80, 'english': 34}}

Dictionary Operations#

  • Membership

  • Iteration

print(s)

'name' not in s
{'name': 'Fahad', 'college': 'lms', 'sem': 4, 'subjects': {'AI': 80, 'english': 34}}
False
d = {'name':'Fahad','gender':'male','age':20}

for i in d:
  print(i,d[i])
name Fahad
gender male
age 20

Dictionary Functions#

# len/sorted
len(d)
print(d)
sorted(d,reverse=True)
max(d)
{'name': 'Fahad', 'gender': 'male', 'age': 20}
'name'
# items/keys/values
print(d)

print(d.items())
print(d.keys())
print(d.values())
{'name': 'Fahad', 'gender': 'male', 'age': 20}
dict_items([('name', 'Fahad'), ('gender', 'male'), ('age', 20)])
dict_keys(['name', 'gender', 'age'])
dict_values(['Fahad', 'male', 20])
# update
d1 = {1:2,3:4,4:5}
d2 = {4:7,6:8}

d1.update(d2)
print(d1)
{1: 2, 3: 4, 4: 7, 6: 8}

Dictionary Comprehension#

image.png

# print 1st 10 numbers and their squares
{i:i**2 for i in range(1,11)}
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}