Introduction to Data Structures in Python
By: Mahadev Easwar
Tags: Data Structures, Programming, Python, Python Programming, Technology

What is a Data Structure?

A data structure is a format for storing, organizing, and processing data. They are the fundamental constructs around which powerful algorithms are built.

List in Python

A list is a data structure that contains multiple items, comma separated and enclosed within square brackets. The items within a list can be of varying data type, including another list. It can be modified after creation(mutable). The elements in a list are indexed, with 0 being the first index.

I hear you. Enough theory, let’s code.

# Creating a list with varying elements including another list

dlist = [10,'element',[100,200,'inlist']]

print(dlist)

>>> [10, 'element', [100, 200, 'inlist']] # Accessing elements in a list

dlist[1]

>>> 'element' dlist[0:2]

>>> [10, 'element'] dlist[-1]

>>> [100, 200, 'inlist'] # Accessing elements inside the embedded list

dlist[-1][2]

>>> 'inlist' # Iterating over a string

list('element')

>>> ['e', 'l', 'e', 'm', 'e', 'n', 't']

Like I mentioned before, index starts with 0 in Python. But you must be wondering when I mention [0:2], why the 3rd element in the list did not get printed. This is because when accessing lists like [0,range], only the elements till the index of (range-1) are returned. Elements inside an embedded list can be accessed using multiple square brackets as shown above.

Lists provide the following functionalities :

append insert pop remove sort extend

# Adding a new element to the list

dlist.append('new_append')

>>> [10, 'element', [100, 200, 'inlist'], 'new_append'] # Inserting a new element using index

dlist.insert(1,'position_one')

>>> [10, 'position_one', 'element', [100, 200, 'inlist'], 'new_append'] # Removing value from the list

dlist.remove('element')

>>> [10, 'position_one', [100, 200, 'inlist'], 'new_append'] # Pop out the last element in the list

dlist.pop()

>>> 'new_append'

print(dlist)

>>> [10, 'position_one', [100, 200, 'inlist']] # Pop element using index

dlist.pop(1)

>>> 'position_one'

print(dlist)

>>> [10, [100, 200, 'inlist']] # New list created & sorted with inbuilt function

nlist = [50,20,70,40]

nlist.sort()

print(nlist)

>>> [20, 40, 50, 70]

nlist.sort(reverse=True)

print(nlist)

>>> [70, 50, 40, 20] # Extending a list with elements from another list

dlist.extend(nlist)

print(dlist)

>>> [10, [100, 200, 'inlist'], 70, 50, 40, 20] # Lists can also be concatenated

clist = nlist + dlist

print(clist)

>>> [70, 50, 40, 20, 10, [100, 200, 'inlist']]

By default the sort function for lists has the parameter (reverse=False), meaning, the list will be returned in ascending order if the sort function is called

If (reverse=True), the list will be returned in descending order

The extend function takes all elements from the list passed as argument and appends them to the calling list

The append function will not work the same way. Passing a list as argument to the function will append it as a list element to the calling list as shown below

dlist.append(nlist)

print(dlist)

>>> [10, [100, 200, 'inlist'], 70, 50, 40, 20, [70, 50, 40, 20]]

List Comprehensions plays an interesting role in helping code in a clear & concise way

List Comprehensions are more efficient than for loops

Checkout the example below to understand how.

# Using for loops with list

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

b = []

for i in a:

if i%2!=0:

b.append(i*2)

else:

b.append(i)

print(b)

>>> [2, 2, 6, 4, 10] # Using list comprehension

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

b = [var*2 if var%2!=0 else var for var in a ]

print(b)

>>> [2, 2, 6, 4, 10]

Set in Python

Sets are unordered and cannot contain duplicate values. Set items cannot be accessed using index. Items in a set are enclosed within curly braces {}.

# Creating a set

var = {'alphabet','item','element'}

print(var)

>>> {'alphabet', 'element', 'item'} # Iterating over a string

set('element')

>>> {'e', 'l', 'm', 'n', 't'} vel = {'item','term','ball'} # Intersection of sets

vel.intersection(var)

>>> {'item'} # Difference of sets

var.difference(vel)

>>> {'alphabet', 'element'} # Union of sets

var.union(vel)

>>> {'alphabet', 'term', 'item', 'ball', 'element'} # Removing element from a set

var.remove('item')

var

>>> {'alphabet', 'element'}

Intersection of sets return the elements which are present in both the sets

Difference of sets return the elements which are present in the calling set, but not present in the set passed as an argument

Union of sets returns all the distinct elements put together

Set function can also come in handy when we need the distinct elements from a list

The ‘issubset’ function helps checks if all elements of the calling set are present in the set passed as argument

# selecting distinct elements from a list

lst = ['a','a','b','c','d','e','d']

set(lst)

>>> {'a', 'b', 'c', 'd', 'e'} # subset check

a = {1,2,3,4,5}

b = {2,3}

b.issubset(a)

>>> True

Dictionary in Python

Dictionaries are collections which are unordered, enclosed within curly braces {} and stored as key-value pairs.

Elements in a dictionary can be accessed using a key instead of index

If we have a dictionary using same key for multiple values, the value stored will be the one mapped with the last key

# Creating a dictionary

d = {'country':'India','currency':'rupees','capital':'Delhi'} # Accessing element from dictionary

d['currency']

>>> 'rupees' # Same key with multiple values

d = {'country':'India','capital':'Delhi','currency':'dollar', 'currency':'rupees'}

d

>>> {'country': 'India', 'capital': 'Delhi', 'currency': 'rupees'} # Modifying values in a dictionary

d['capital'] = 'New Delhi'

d

>>> {'country': 'India', 'capital': 'New Delhi', 'currency': 'rupees'} # Adding new element to the dictionary

d['culture'] = 'Diverse'

d

>>> {'country': 'India','capital': 'New Delhi','currency': 'rupees',

'culture': 'Diverse'}

Dictionaries are very useful when it comes to accessing elements quickly, they use hashing

It does not iterate over all the items to find the value like lists. Instead uses the key to directly access the item value

ldict = {'country':'India','capital':'Delhi',

'MCs':['Chennai','Delhi','Kolkata','Mumbai']} # Accessing keys, values of a dictionary

ldict.keys()

>>> dict_keys(['country', 'capital', 'MCs']) ldict.values()

>>> dict_values(['India', 'Delhi', ['Chennai', 'Delhi', 'Kolkata', 'Mumbai']]) # Accessing respective key-value of each element

ldict.items()

>>> dict_items([('country', 'India'), ('capital', 'Delhi'), ('MCs', ['Chennai', 'Delhi', 'Kolkata', 'Mumbai'])]) # Accessing value using get function

ldict.get('country')

>>> 'India' # Accessing one of the above in the form of a list

list(ldict.keys())

>>> ['country', 'capital', 'MCs']

Dictionaries are quick, easy to use, and flexible

A dictionary can be extended to accommodate the key-value pairs from another dictionary using the update function

# Updating a dictionary

nd = {'first':'one','second':'two'}

ldict.update(nd)

ldict

>>> {'country': 'India',

'capital': 'Delhi',

'MCs': ['Chennai', 'Delhi', 'Kolkata', 'Mumbai'],

'first': 'one',

'second': 'two'} # Removing an element from the dictionary

del ldict['second']

ldict

>>> {'country': 'India','capital': 'Delhi','MCs': ['Chennai', 'Delhi', 'Kolkata', 'Mumbai'],'first': 'one'}

Tuple in Python

Tuples are another data structure similar to lists, but they are immutable. They are ordered and values can be accessed using index. The values are comma-separated and enclosed within parenthesis.

No element can be added, removed or modified once a tuple is created

Tuple can have duplicate values since they are indexed

# Creating a tuple

tup = (1,2,4,2,5)

tup

>>> (1, 3, 4, 3, 5) # Count of occurrence of value

tup.count(3)

>>> 2 # Index of a value

tup.index(5)

>>> 4 # Max and min values from a tuple

min(tup)

>>> 1

max(tup)

>>> 5 # Concatenating tuples

tt = (5, 6, 7, [10, 30])

tup+tt

>>> (1, 3, 4, 3, 5, 5, 6, 7, [10, 30]) # Membership

6 in tt

>>> True

Although a tuple is immutable, if a mutable object is present in the tuple, value of that object can be modified. Similar to lists, slicing operations are allowed on tuples using the index of the values.

# List within a tuple

tt = (5,6,7,[10,20])

tt

>>> (5,6,7,[10,20]) # Slicing values in a tuple

tt[1:3]

(6, 7) # Modifying the value inside the list

tt[3][1] = 30

tt

>>> (5, 6, 7, [10, 30])

Tuple iteration is faster than iterating through a list

Tuple packing and unpacking are the most useful operations when it comes to passing multiple arguments to a function or getting multiple values in the response and assigning to respective attributes/fields