L
LLLOS.ai
Learn
L

Chapter 5 — Working With Data In Python

Class 11 · Computer Science

Overview

Chapter 5 — Working With Data In Python Master Diagram

Introduction: "Working with Data in Python" introduces how data is represented, stored and manipulated in Python programs. The chapter covers core built-in data types (numbers, strings, booleans), compound data structures (lists, tuples, sets, dictionaries), basic input/output and type conversion, and common operations and methods used to clean, transform and analyze simple datasets. Importance: Understanding these concepts gives students the foundation to solve real problems, prepare data for algorithms, and build larger programs. Mastery of data handling is essential for algorithm development, debugging, and later topics like databases, data science and file handling. Key themes: data types and literals, variables and naming rules, reading and displaying data, type conversion and validation, operators and precedence, string manipulation (indexing, slicing, methods), sequence operations (lists/tuples: creation, indexing, slicing, methods), sets and dictionaries (usage and common operations), iteration over data, and basic data processing patterns (search, aggregate, sort). What the student will learn: students will learn to declare and use variables, distinguish and convert data…

Learning Objectives

  • Define and give examples of built-in Python data types used in working with data (int, float, str, bool, list, tuple, dict, set).
  • Explain indexing and slicing for strings, lists and tuples and trace outputs of code snippets that use them.
  • Distinguish between mutable and immutable sequence types and describe implications for data manipulation.
  • Demonstrate use of common string methods (split, join, strip, replace, upper/lower, find) to process textual data.
  • Apply list and dictionary methods (append, extend, insert, remove, pop, sort, reverse, keys, values, items, get, update) to solve data manipulation tasks.
  • Use list comprehensions and generator expressions to create and transform collections concisely and predict their outputs.
  • Implement nested data structures (lists of lists, dictionaries containing lists/dicts) and write code to access and update nested elements.
  • Write Python programs to read from and write to text files using open(), read(), readline(), readlines(), write(), and with context managers.

Topics in this chapter

20 topics · tap a topic title to jump straight to it.

⚙️1

Introduction to Working with Data

💻 COMPUTER SCIENCE / IT

Introduction to Working with Data

Key Point: Mean (average): mean = (x1 + x2 + ... + xn) / n

What is data? Data are pieces of information — numbers, text, True/False values or more complex records — that describe events, measurements, observations or transactions.

Why work with data? In computing and everyday life we collect, store, analyze and present data to make decisions (e.g., student marks, sales figures, weather records).

Types of data:

  • Primitive: integers, floats, strings, booleans.
  • Structured: tables (rows and columns), CSV, JSON; unstructured: free text, images.

Common Python containers: list (ordered collection), tuple (ordered immutable), dict (key→value mapping), set (unique items). These are used to store and manipulate data in memory.

Typical data workflow: collection → cleaning/preprocessing → storage → analysis → visualization → interpretation. Cleaning includes handling missing values, converting data types, removing duplicates and validating ranges.

Basic operations: indexing/slicing, iterating (for-loops, comprehensions), aggregations (sum, count, min, max), and summary statistics (mean, median, mode, variance). For files and exchange formats you use CSV or JSON; Python has built-in csv/json modules and higher-level libraries such as pandas for tabular data.

Practical tips: always check data types, handle missing or invalid entries before analysis, and start with simple visualizations to understand distribution and trends.

📌 Examples
  • Student marks table: rows are students, columns are subjects and total marks. Use lists/dicts to store records and compute average marks, highest scorer, grade distribution.
  • Daily temperature readings: a time-series of floats. Use a list of (date, temperature) tuples, compute monthly average, and plot a line chart to show trends.
  • Store sales transactions in CSV: columns like date, product_id, quantity, price. Read CSV, convert quantities/prices to numeric types, compute total revenue per product.
  • Survey responses in JSON: each response as a JSON object. Use Python's json module to load data, count categorical responses, and find common answers.
  • Sensor data stream: real-time numeric values with occasional missing readings. Detect and interpolate or remove missing values before computing statistics.
🧮 Formulas
  1. \[Mean (average): mean = (x1 + x2 + ... + xn) / n\]
  2. \[Median: the middle value when data are sorted (if n is odd)\]
    \[or average of two middle values (if n is even)\]
  3. \[Mode: the value that appears most frequently in the dataset\]
  4. \[Variance: σ² = (1/n) * Σ (xi - mean)²\]
  5. \[Standard deviation: σ = sqrt(variance)\]
  6. \[Percentage: percent = (part / whole) × 100\]
💻2

Variables and Identifiers

💻 COMPUTER SCIENCE / IT

Variables and Identifiers

Key Point: Assignment: variable = expression (example: x = 5)

What is a Variable?
A variable is a name that refers to a value stored in memory. In Python a variable name (identifier) is bound to an object; the object has a value and a type. Python is dynamically typed: the same variable name can refer to objects of different types at different times.

What is an Identifier?
An identifier is the name used to identify a variable, function, class, module, or other object. Identifiers in Python are sequences of letters (a–z, A–Z), digits (0–9) and underscores (_), but must start with a letter or underscore.

Rules for Identifiers

  • Must begin with a letter (a–z, A–Z) or underscore (_).
  • Can contain letters, digits and underscores only.
  • Case-sensitive: age and Age are different identifiers.
  • Cannot be a Python reserved keyword (for, if, while, def, class, True, None, etc.).
  • Should not start with digits and should not contain special characters or spaces.

Naming Conventions (Good Practices)
Use meaningful names, prefer snake_case for variables and functions (example: student_marks), limit length to readable size, avoid single-letter names except for counters (i, j) and avoid names that shadow built-ins (like list, str).

How Variables Work (Conceptual Memory Model)
Think of a variable name as a label attached to an object stored in memory. When you assign x = 10, the name x points to an integer object with value 10. Assigning x = 'hello' rebinds the name x to a string object; the old integer object may be reclaimed by garbage collection if no names refer to it.

Scope and Lifetime (Brief)
Scope determines where an identifier is accessible: global scope (module-level), local scope (inside functions), and nested scopes. Lifetime is how long the binding exists — local variables exist during function execution; globals exist while the program runs (or module is loaded).

Common Operations

# assignment
count = 5

# multiple assignment
a, b = 1, 2

# swapping without temp
a, b = b, a

# augmented assignment
count += 1

# type conversion (casting)
age = int('18')

Errors to Watch For

  • SyntaxError if identifier starts with digit or has illegal character: 2name, first-name.
  • NameError when using an identifier that has not been defined.
  • Shadowing built-ins can cause subtle bugs (for example, assigning list = [1,2] then calling list()).

📌 Examples
  • age = 16 # integer variable name = 'Rahul' # string variable is_enrolled = True # boolean variable
  • x, y, z = 10, 20, 30 # multiple assignment x, y = y, x # swap x and y
  • balance = 1500.75 balance += 500 # augmented assignment; balance becomes 2000.75
  • # invalid identifiers # 2count = 5 # SyntaxError: cannot start with digit # first-name = 'A' # SyntaxError: '-' not allowed in identifier
  • # scope example user = 'global' def greet(): user = 'local' # local variable, different from global user print(user) # greet() prints 'local', global user remains 'global'
🧮 Formulas
  1. \[Assignment: variable = expression (example: x = 5)\]
  2. \[Multiple assignment: a\]
    \[b\]
    \[c = v1\]
    \[v2\]
    \[v3 (example: a\]
    \[b = 1, 2)\]
  3. \[Swap without temp: a\]
    \[b = b\]
    \[a\]
  4. \[Augmented assignment: var op= value (example: count += 1\]
    \[total *= 2)\]
  5. \[Type conversion (casting): new_var = type(value) (example: n = int('42'))\]
  6. \[Identifier rule summary: starts_with ∈ {letter\]
    \[underscore} AND all_chars ∈ {letters\]
    \[digits\]
    \[underscore} AND not a reserved_keyword\]
📊3

Data Types and Literals

💻 COMPUTER SCIENCE / IT

Data Types and Literals

Key Point: type(x) # returns the type of x

Data types specify what kind of value a variable can hold and what operations are valid on it. In Python, values are created by writing literals — fixed notations for data (like 10, 'abc', [1,2]).

Main categories:

  • Numeric types
    • int – integers without fractional part (e.g., 42, -7).
    • float – floating-point numbers with decimals (e.g., 3.14, -0.5).
    • complex – complex numbers with real and imaginary parts (e.g., 2+3j).
  • Text
    • str – sequence of characters. Literals can use single, double or triple quotes: 'hi', "hello", '''multi-line'''. Supports indexing, slicing and many methods.
  • Booleanbool which has two literals: True and False. Used for conditions and logical operations.
  • None – the None literal represents absence of a value.
  • Collection (compound) types
    • list – ordered, changeable sequence written with square brackets: [1, 2, 3] (mutable).
    • tuple – ordered, fixed sequence written with parentheses: (1, 2, 3) (immutable).
    • set – unordered collection of unique elements written with braces: {1, 2, 3} (mutable, no duplicates).
    • dict – key:value mapping using braces: {'name':'Asha', 'age':16} (mutable, keys unique).

Literals are the concrete notation for values. Examples: numeric literals (0, -3.5), string literals ("CBSE"), boolean (True), collection literals ([], (), {}), and None.

Mutability: lists, sets and dicts are mutable (their contents can change). Strings, tuples, integers, floats and complex numbers are immutable. Understanding immutability helps avoid bugs when sharing objects.

Type checking and conversion: use type(x) or isinstance(x, T) to check types. Convert values with int(), float(), str(), bool(), and constructors for collections like list(), tuple(), set(), dict().

Why it matters (real life): choose appropriate types to represent data accurately — e.g., counts as int, prices/measurements as float, names as str, a contact directory as dict. Wrong type choices lead to incorrect computations or inefficient programs.

📌 Examples
  • Counting students: roll = 30 # int literal
  • Price of book: price = 199.99 # float literal
  • Complex number: z = 4 + 2j # complex literal
  • Name: name = 'Rahul' # string literal (single quotes)
  • Multi-line text: text = '''Line1\nLine2''' # triple-quoted string
  • Boolean check: passed = True # boolean literal
🧮 Formulas
  1. \[type(x) # returns the type of x\]
  2. \[isinstance(x\]
    \[T) # checks if x is of type T\]
  3. \[int(s)\]
    \[float(s)\]
    \[str(x)\]
    \[bool(x) # type conversions\]
  4. \[len(s) # length of sequence or collection\]
  5. \[a + b # addition or concatenation (numbers/strings/lists)\]
  6. \[a * n # repeat sequence or multiply numbers\]
💻4

Type Conversion and Casting

💻 COMPUTER SCIENCE / IT

Type Conversion and Casting

Key Point: int(x) — convert x to integer (float -> truncates toward zero; string -> must be integer-format).

Type conversion (also called casting) in Python is the process of converting a value from one data type to another. This is important when combining values of different types, reading input (which is a string), or preparing data for operations that require specific types.

Two kinds of conversion

  • Implicit conversion (automatic): Python automatically converts one data type to another when it is safe to do so—for example, when an int and a float are used together, the int is converted to float so precision is preserved.
  • Explicit conversion (casting): The programmer converts types using built-in functions such as int(), float(), str(), bool(), etc. This is required when automatic conversion is not possible or when you want a specific result.

Rules & behavior

  • Numeric promotion: int mixed with float → float; float mixed with complex → complex.
  • int(float_value) truncates toward zero (it does not round).
  • Converting from string: the string must represent a valid value for the target type (e.g., "123" → int OK, "12.3" → int raises ValueError unless first converted to float).
  • bool conversions: bool(0) is False; bool(0.0) is False; bool("") is False; any nonzero number or non-empty container is True.
  • Incompatible conversions (like int('abc')) raise ValueError; type mismatches in operations may raise TypeError.
  • Python’s bool is a subclass of int: True == 1 and False == 0, so booleans participate in numeric operations.

Common casting functions

  • int(x) — to integer (truncates floats).
  • float(x) — to floating-point.
  • str(x) — to string.
  • bool(x) — to boolean.
  • complex(a, b) or complex(x) — to complex number.
  • int(string, base) — convert from a string in given base (e.g., base=2 for binary).
  • bin(x), oct(x), hex(x) — convert integer to binary/octal/hex string representation.
  • list(), tuple(), set(), dict() — convert between container types where conversion makes sense.

Short code examples

# implicit conversion
result = 5 + 2.3    # result is 7.3 (int 5 promoted to float)

# explicit conversion
s = '123'
num = int(s)         # 123 (int)
price = 19.95
count = int(price)   # 19 (truncated)

# string + number needs casting
name = 'Alice'
age = 17
greeting = name + ' is ' + str(age) + ' years old'

# base conversion
n = int('1010', 2)   # n == 10

# boolean rules
bool(0)    # False
bool('')   # False
bool([1])  # True

# invalid conversion
# int('12.3')  -> ValueError; first do float('12.3') then int(...)

Understanding when Python converts types automatically and when you must cast explicitly helps avoid errors and data loss (for example, unintended truncation). Use explicit casting when you need a specific type or to validate/clean input data.

📌 Examples
  • Reading numeric input from a user: input() returns a string. Convert to int or float before arithmetic: age = int(input('Age: ')).
  • Concatenating text and numbers: build messages using str(): 'Score: ' + str(score).
  • Currency conversion: multiply float exchange_rate by int quantity (int promoted to float). Example: total = 3 * 74.5 -> 223.5.
  • Sensor data: a temperature sensor returns '23.7' as a string from a device; convert with temp = float(reading) to compute averages.
  • Binary parsing: convert '1101' (binary string) to decimal using int('1101', 2) -> 13.
🧮 Formulas
  1. \[int(x) — convert x to integer (float -> truncates toward zero\]
    \[string -> must be integer-format).\]
  2. \[float(x) — convert x to float (int -> exact\]
    \[string -> must be valid float format).\]
  3. \[str(x) — convert x to string (useful for concatenation and display).\]
  4. \[bool(x) — convert x to boolean (0, 0.0, ''\]
    \[None\]
    \[empty containers -> False\]
    \[otherwise True).\]
  5. \[complex(a\]
    \[b) or complex(x) — produce complex numbers (a + bj).\]
  6. \[int(s\]
    \[base) — parse string s as an integer in given base (2..36).\]
💻5

Operators and Expressions

💻 COMPUTER SCIENCE / IT

Operators and Expressions

Key Point: Arithmetic identities: a + 0 = a, a * 1 = a, a - 0 = a, a / 1 = a

Overview
In Python, an expression is any combination of values, variables and operators that Python can evaluate to produce another value. Operators are special symbols or keywords that perform operations on one or more operands (values or variables). Understanding operators and expressions is essential for writing computations, making decisions and manipulating data.

Types of operators

  • Arithmetic: +, -, *, /, // (floor division), % (modulus), ** (exponent). These perform numeric calculations. Example: 3 + 4 * 2**2.
  • Comparison (Relational): ==, !=, <, <=, >, >=. They compare values and return True or False.
  • Logical: and, or, not. Combine boolean expressions. Use short-circuit evaluation.
  • Assignment: = assigns a value. Augmented assignment like +=, -=, *= updates a variable: x += 3 is x = x + 3.
  • Bitwise: &, |, ^, ~, <<, >> operate on integer bit representations.
  • Membership: in, not in — check presence in sequences or collections.
  • Identity: is, is not — check whether two names refer to the same object (not just equal values).

Expressions and evaluation
An expression can be simple (5, x) or compound ((a + b) * c). Evaluation follows operator precedence (higher-precedence operators evaluated first) and associativity (left-to-right or right-to-left for operators with same precedence). Python also performs implicit type conversions for some operations (e.g., 1 + 2.0 -> 3.0) and allows explicit conversions via int(), float(), str(), bool().

Precedence highlights
Important precedence order (from higher to lower): parentheses, exponentiation (** right-to-left), unary +/-, *, /, //, %, +, -, bitwise shifts, bitwise AND/OR/XOR, comparison, not, and, or. Use parentheses to force a specific evaluation order.

Short-circuiting
Logical and and or use short-circuit evaluation: for A and B, if A is false, B is not evaluated; for A or B, if A is true, B is not evaluated. This is useful for guarding operations (e.g., x and x.method()).

Operator overloading
Some operators behave differently for different operand types: e.g., + adds numbers but concatenates strings or lists ('a' + 'b' -> 'ab', [1] + [2] -> [1,2]).

Common pitfalls

  • Using is instead of == for value comparison (use == to compare values; is checks identity).
  • Unexpected integer division vs floor division: in Python 3, / produces float, use // for floor division.
  • Relying on implicit type conversion in mixed-type expressions can produce unexpected floats or strings; prefer explicit conversion when needed.

Small Python code examples

# arithmetic and precedence
a, b, c = 2, 3, 4
result = a + b * c        # 2 + (3*4) = 14

# short-circuit example
user = None
name = user and user.name  # user is None -> name is None (user.name not evaluated)

# bitwise example
x = 6        # 0b110
y = 3        # 0b011
z = x & y    # 0b010 -> 2

# membership
s = 'hello'
'in' in s    # True

# augmented assignment
count = 0
count += 5   # 5

# swapping without temp
x, y = y, x

How this applies in real life
Operators and expressions model everyday computations: banking calculations (interest using arithmetic operators and precedence), decision logic in apps (comparison + logical operators to determine eligibility), string manipulation in text processing (concatenation, membership), bitwise operations in low-level hardware control, and short-circuit checks for safe resource access.

📌 Examples
  • Calculator (arithmetic & precedence): expression for final amount: final = principal + interest_rate * principal; precedence ensures multiplication before addition.
  • Eligibility check (comparison + logical): if age >= 18 and has_id: allow entry — both conditions must be True.
  • Safe attribute access (short-circuit): username = user and user.name — avoids accessing user.name when user is None.
  • String concatenation (operator overloading): full_name = first_name + ' ' + last_name.
  • Even/odd check (bitwise): even if (n & 1) == 0 else odd — fast test using bitwise AND.
  • Swapping values (assignment tuple): a, b = b, a — swap without a temporary variable.
🧮 Formulas
  1. \[Arithmetic identities: a + 0 = a\]
    \[a * 1 = a\]
    \[a - 0 = a\]
    \[a / 1 = a\]
  2. \[Modulus: a = b * (a // b) + (a % b) (quotient and remainder relationship)\]
  3. \[De Morgan's laws: not (A and B) == (not A) or (not B)\]
    \[not (A or B) == (not A) and (not B)\]
  4. \[Operator precedence (important order high→low): parentheses ()\]
    \[exponentiation ** (right-to-left)\]
    \[unary + -, *, /, //, %, + -, << >>, &, ^, |\]
    \[comparisons\]
    \[not\]
    \[and\]
    \[or\]
  5. \[Short-circuit logic: (A and B) returns A if A is falsy\]
    \[otherwise returns B\]
    \[(A or B) returns A if A is truthy\]
    \[otherwise returns B\]
  6. \[Type conversion: numeric mixing — int + float -> float\]
    \[explicit conversions: int(x)\]
    \[float(x)\]
    \[str(x)\]
    \[bool(x)\]
💻6

Strings

💻 COMPUTER SCIENCE / IT

Strings

Key Point: Indexing: s[i] # character at index i (0-based). Negative: s[-1] last char

What is a string?
A string is an ordered sequence of characters used to store and manipulate text. In Python a string literal is written between single quotes (') or double quotes (") or triple quotes for multi-line text. Strings are immutable — once created, their characters cannot be changed in place.

Creating and representing strings

  • s = 'Hello' or s = "Hello" or s = '''Multi\nline'''
  • Escape sequences: \n (newline), \t (tab), \\ (backslash), \', \"
  • Raw strings: r'C:\folder\file' treats backslashes literally

Indexing and slicing
Strings are indexed from 0. You can access characters and sub-strings using indexing and slicing.

  • Indexing: s[i] gives the character at position i (negative indices count from the end)
  • Slicing: s[i:j:k] returns a substring from index i up to j (exclusive) with step k; omitted values default to start, end, or step 1

Common operations

  • Concatenation: s + t
  • Repetition: s * n
  • Membership: sub in s checks whether sub occurs in s
  • Length: len(s)
  • Methods: s.upper(), s.lower(), s.strip(), s.split(sep), sep.join(list), s.replace(old,new), s.find(sub), s.count(ch)

Immutability and consequences
Because strings are immutable, operations that appear to modify a string actually create and return a new string. For example, s = s.replace('a','b') assigns a new string to the variable s; the old string is unchanged in memory until garbage-collected.

Formatting and templates
Strings are commonly used to format output and generate templates. You can use str.format(), f-strings (f"Hello {name}"), or % formatting to insert values into text.

Use in data handling
Strings are central in reading/writing text files, parsing CSV or log lines, processing user input, building URLs and JSON, validating input (emails, phone numbers), and producing human-readable reports.

📌 Examples
  • Basic: s = 'Hello World' ; print(s[0]) # 'H' ; print(s[-1]) # 'd'
  • Slicing: s = 'ABCDEFGHI' ; s[1:7:2] # 'BDF'
  • Concatenation & repetition: 'Hi' + '!'*3 # 'Hi!!!'
  • Split & join: line = 'apple,banana,pear' ; parts = line.split(',') ; ','.join(parts)
  • Search & replace: s.find('cat') ; s.replace('cat','dog')
  • Formatting: name = 'Asha' ; age = 16 ; f'Name: {name}, Age: {age}'
🧮 Formulas
  1. \[Indexing: s[i] # character at index i (0-based)\]
    \[Negative: s[-1] last char\]
  2. \[Slicing: s[i:j:k] # substring from i to j-1 with step k\]
    \[Defaults: i=0\]
    \[j=len(s)\]
    \[k=1\]
  3. \[Length: len(s) # number of characters\]
  4. \[Concatenation: s + t # joins two strings\]
  5. \[Repetition: s * n # repeats s n times\]
  6. \[Membership: sub in s # True if sub appears in s\]
💻7

Lists

💻 COMPUTER SCIENCE / IT

Lists

Key Point: Indexing: lst[i] (i starts from 0); negative: lst[-1] is last element

What is a list?

A list in Python is an ordered, mutable collection of items. Items can be of different data types (heterogeneous) and duplicates are allowed. Lists are used to store a sequence of values and provide many built-in operations and methods to manipulate that sequence.

Creating lists

# empty list
lst = []
# list with values
nums = [10, 20, 30]
mixed = [1, 'apple', 3.14, True]
# nested list (list of lists)
matrix = [[1,2,3], [4,5,6], [7,8,9]]

Key characteristics

  • Ordered: items have a definite order and each item has an index (starting at 0).
  • Mutable: elements can be changed, added or removed after creation.
  • Heterogeneous: elements of different types can coexist.
  • Allow duplicates: same value can appear multiple times.

Indexing and slicing

Access items by index: lst[0] is first item. Negative indices count from the end: lst[-1] is last item. Slicing returns a sublist: lst[start:stop:step].

nums = [10,20,30,40,50]
nums[0]      # 10
nums[-1]     # 50
nums[1:4]    # [20,30,40]
nums[::2]    # [10,30,50]

Common list operations and methods

  • len(lst) — number of elements.
  • in — membership test: if x in lst:.
  • Concatenation: lst1 + lst2. Repetition: lst * n.
  • append(x) — add x to end.
  • insert(i, x) — insert x at index i.
  • extend(iterable) — add all elements of an iterable.
  • remove(x) — remove first occurrence of x.
  • pop([i]) — remove and return element at index i (default last).
  • index(x), count(x) — locate/count occurrences.
  • sort() and reverse() — in-place sorting and reversal. sorted(lst) returns a new sorted list.
  • copy() or slicing lst[:] — shallow copy. Use copy.deepcopy() for nested lists.

Iteration and enumeration

for item in lst:
    print(item)
# with index
for i, v in enumerate(lst):
    print(i, v)

Nested lists (2D lists / matrices)

Lists can contain other lists. Access by chained indices: matrix[row][col]. Useful to represent tables or matrices.

List comprehensions (concise construction)

squares = [x*x for x in range(1,6)]  # [1,4,9,16,25]
filtered = [x for x in nums if x > 20]

Practical tips

  • Use append for incremental building, extend to merge lists.
  • Prefer sorted() if you need original list unchanged.
  • Beware of aliasing: b = a makes both names refer to same list; use a.copy() or a[:] to copy.
📌 Examples
  • Example 1: Student marks marks = [78, 85, 62, 91, 73] # average = sum(marks) / len(marks) # find highest: max(marks), lowest: min(marks)
  • Example 2: Shopping list (mutable) shopping = ['milk', 'eggs', 'bread'] shopping.append('butter') # add item shopping.remove('eggs') # remove item
  • Example 3: Inventory with counts (parallel lists) items = ['pen', 'notebook', 'eraser'] qty = [20, 10, 5] # quantity of 'notebook' -> qty[items.index('notebook')] # 10
  • Example 4: Sensor readings (time series) readings = [23.4, 24.1, 22.8, 23.9] # moving average, plot readings vs time
  • Example 5: Matrix as nested list matrix = [[1,2,3],[4,5,6],[7,8,9]] # element at row2 col3: matrix[1][2] -> 6
🧮 Formulas
  1. \[Indexing: lst[i] (i starts from 0)\]
    \[negative: lst[-1] is last element\]
  2. \[Slicing: lst[start:stop:step] (returns sublist from start to stop-1)\]
  3. \[Length: n = len(lst)\]
  4. \[Concatenate: lst3 = lst1 + lst2\]
  5. \[Repeat: lst2 = lst * k\]
  6. \[Membership: x in lst (True/False)\]
💻8

Tuples

💻 COMPUTER SCIENCE / IT

Tuples

Key Point: Indexing: element = t[i] where i in 0..len(t)-1

What is a tuple?

A tuple is an ordered, immutable collection of items in Python. Like a list, a tuple can hold heterogeneous elements (different data types) and preserves the insertion order, but once created its elements cannot be changed (no item assignment, insertion, or deletion). Tuples are written with parentheses () or simply comma-separated values.

Syntax & basic examples

# creation
t1 = (1, 2, 3)
# parentheses optional for simple tuples
t2 = 4, 5, 6
# single element tuple needs a trailing comma
single = (10,)
# empty tuple
empty = ()

Properties

  • Ordered: elements have a fixed order and can be accessed by index (0-based).
  • Immutable: you cannot change elements after creation. Any attempt to assign to an index raises an error.
  • Heterogeneous: elements of different types allowed.
  • Hashable (sometimes): a tuple is hashable if all its elements are hashable, so it can be used as a dictionary key.
  • Supports many sequence operations: indexing, slicing, concatenation, repetition, membership test, length, iteration.

Common operations (with examples)

t = (10, 20, 30, 'a')
# indexing
x = t[1]        # 20
# slicing
s = t[1:3]      # (20, 30)
# concatenation
t3 = t + (100,)
# repetition
r = t * 2       # (10,20,30,'a',10,20,30,'a')
# membership
is_in = 20 in t # True
# length
n = len(t)      # 4
# methods: count and index
cnt = t.count(20)
pos = t.index('a')
# unpacking
a, b, c, d = t
# extended unpacking
first, *middle, last = (1,2,3,4,5)

Immutability explained

Because tuples are immutable, operations that seem to change a tuple actually create a new tuple. For example concatenation t + u returns a new tuple; converting to a list, modifying, then converting back is a common workaround.

t = (1,2,3)
# this raises TypeError
# t[0] = 10
# workaround
lst = list(t)
lst[0] = 10
t = tuple(lst)

When to use tuples (advantages)

  • When data should not change (fixed records like coordinates, RGB colors, date components).
  • As keys in dictionaries (if elements are hashable) or elements in sets.
  • Returning multiple values from a function (function returns a tuple by default).
  • Tuples are slightly faster and use less memory than lists for fixed-size sequences.

Examples of real-life mapping

  • Geographic coordinate: (latitude, longitude)
  • RGB color: (R, G, B)
  • Date: (year, month, day)
  • Database record row (id, name, age)

Notes for Class 11 students

  • Understand difference between tuple and list: mutability is the key difference.
  • Learn tuple packing/unpacking and common operations (indexing, slicing, concatenation, repetition, membership).
  • Practice with small programs: returning multiple values, using tuples as keys in dicts, and converting between list & tuple.
📌 Examples
  • Return multiple values from a function: def min_max(numbers): return (min(numbers), max(numbers)) a, b = min_max([3,1,9,4]) # a=1, b=9
  • Coordinate example: point = (12.9716, 77.5946) # (latitude, longitude) lat = point[0] lon = point[1]
  • Using tuple as dict key: location = {(12.9716,77.5946): 'Bengaluru'} print(location[(12.9716,77.5946)])
  • Unpacking with extended form: values = (1,2,3,4,5) first, *middle, last = values # first=1, middle=[2,3,4], last=5
  • Immutability workaround: t = (1,2,3) lst = list(t) lst.append(4) t = tuple(lst) # now (1,2,3,4)
🧮 Formulas
  1. \[Indexing: element = t[i] where i in 0..len(t)-1\]
  2. \[Slicing: subtuple = t[start:stop] returns elements start..stop-1\]
  3. \[Concatenation: t3 = t1 + t2 (creates a new tuple)\]
  4. \[Repetition: t2 = t1 * n (repeats contents n times)\]
  5. \[Length: n = len(t)\]
  6. \[Membership: x in t (True if x is one of the elements)\]
💻9

Sets

💻 COMPUTER SCIENCE / IT

Sets

Key Point: A ∪ B = {x | x ∈ A or x ∈ B} (union) — Python: A | B or A.union(B)

What is a set? A set is an unordered collection of distinct elements. In Python, sets store unique items and support mathematical set operations (union, intersection, difference, etc.). Sets are mutable (you can add/remove elements) but their elements must be immutable (e.g., numbers, strings, tuples).

How to create sets in Python

  • Using curly braces: {1, 2, 3}.
  • Using the constructor: set([1, 2, 3]) or set('abc').
  • Note: {} creates an empty dictionary — use set() for an empty set.

Important properties

  • Uniqueness: duplicates are automatically removed.
  • Unordered: no guaranteed index or order.
  • Mutable container: methods like add, remove, discard, pop, clear are available.
  • Set elements must be hashable (immutable types).

Common operations and methods

  • Union: A | B or A.union(B) — elements in A or B.
  • Intersection: A & B or A.intersection(B) — elements in both A and B.
  • Difference: A - B or A.difference(B) — elements in A but not in B.
  • Symmetric difference: A ^ B or A.symmetric_difference(B) — elements in A or B but not both.
  • Subset / superset checks: A.issubset(B), A.issuperset(B).
  • Membership: x in A (fast, average O(1)).

Why use sets? They are ideal for removing duplicates, membership testing, and performing mathematical set operations efficiently.

Simple Python example (illustration)

students = ['Anita', 'Ravi', 'Anita', 'Sunil']
unique = set(students)   # {'Anita', 'Ravi', 'Sunil'}
unique.add('Meera')
if 'Ravi' in unique:
    unique.remove('Ravi')
📌 Examples
  • Create, add, remove: code: s = {1, 2, 3} s.add(4) # s -> {1,2,3,4} s.discard(2) # s -> {1,3,4} # discard does not raise error if element missing; remove does
  • Union and intersection: code: A = {1, 2, 3} B = {3, 4, 5} A | B # -> {1,2,3,4,5} (union) A & B # -> {3} (intersection) A - B # -> {1,2} (difference) A ^ B # -> {1,2,4,5} (symmetric difference)
  • Remove duplicates from a list: code: nums = [2,2,3,5,3] unique_nums = list(set(nums)) # -> [2,3,5] (order not guaranteed)
  • Real-life scheduling (common free slots): code: alice = {'Mon9','Tue10','Wed11'} bob = {'Tue10','Thu9'} common = alice & bob # -> {'Tue10'} (time slots both are free)
  • Exclusive customers to store A (difference): code: A = {'cust1','cust2','cust3'} B = {'cust2','cust4'} only_A = A - B # -> {'cust1','cust3'}
🧮 Formulas
  1. \[A ∪ B = {x | x ∈ A or x ∈ B} (union) — Python: A | B or A.union(B)\]
  2. \[A ∩ B = {x | x ∈ A and x ∈ B} (intersection) — Python: A & B or A.intersection(B)\]
  3. \[A \ B = {x | x ∈ A and x ∉ B} (difference) — Python: A - B or A.difference(B)\]
  4. \[A Δ B = (A \ B) ∪ (B \ A) (symmetric difference) — Python: A ^ B or A.symmetric_difference(B)\]
  5. \[|A| = number of elements in A (cardinality) — Python: len(A)\]
  6. \[Subset: A ⊆ B iff every x ∈ A is also in B — Python: A.issubset(B)\]
💻10

Dictionaries

💻 COMPUTER SCIENCE / IT

Dictionaries

Key Point: len(d) -> number of key:value pairs

What is a Dictionary?

A dictionary in Python is a built-in collection type that stores data as key:value pairs. Each key maps to a value. Keys must be unique and immutable (for example: strings, numbers, tuples), while values can be any Python object (numbers, strings, lists, other dictionaries, etc.).

Characteristics

  • Mapping type — data accessed by key, not by index.
  • Keys are unique; assigning the same key again updates the value.
  • Mutable — you can add, change or remove items.
  • Insertion order is preserved in Python 3.7+ (implementation detail in 3.6).

Basic operations and syntax

  • Creation: d = {'a': 1, 'b': 2} or d = dict().
  • Access: value = d['a'] (raises KeyError if key missing) or value = d.get('a', default) (safer).
  • Insert / Update: d['c'] = 3.
  • Delete: del d['b'] or d.pop('b', default) or d.popitem().
  • Membership: 'a' in d returns True/False (checks keys).
  • Iteration: for k in d: or for k, v in d.items():.

Common methods

  • d.keys() — view of keys.
  • d.values() — view of values.
  • d.items() — view of (key, value) pairs.
  • d.update(other) — merge another dict (overwrites on same keys).
  • d.clear() — remove all items.
  • d.copy() — shallow copy.
  • dict.fromkeys(seq, value) — create dict with keys from seq and same value.
  • d.setdefault(key, default) — get or set default value for key.

Dictionary comprehensions

Similar to list comprehensions: {k: v for k, v in iterable}. Useful to build transformed dictionaries in one expression.

Nested dictionaries

Dictionaries can contain other dictionaries as values, enabling structured records (e.g., student -> {name, marks}). Access uses multiple key lookups: students['s1']['marks'].

Performance

Dictionaries are implemented with hash tables. Average time complexity for lookup, insert and delete is O(1). In rare worst-case situations (many hash collisions) complexity can degrade toward O(n).

When to use a dictionary?

  • When you need a lookup by a unique key (e.g., phone number by name).
  • When representing records/objects with named fields.
  • When counting/frequency mapping (word counts, item counts).
📌 Examples
  • Phonebook (simple): phone = {'Alice':'9876543210', 'Bob':'9123456780'}; phone['Alice'] gives '9876543210'.
  • Student records (nested): students = {'s101': {'name':'Rahul', 'marks': 85}, 's102': {'name':'Anita', 'marks': 92}}; students['s101']['marks'] -> 85.
  • Inventory update: stock = {'pens': 10, 'notebooks': 5}; stock['pens'] = stock.get('pens',0) - 2 updates quantity; stock.update({'eraser':3}) adds new item.
  • Counting words: text = 'to be or not to be'; freq = {}; for w in text.split(): freq[w] = freq.get(w,0)+1; result: {'to':2, 'be':2, 'or':1, 'not':1}.
  • Merging dictionaries: d3 = {**d1, **d2} (Python 3.5+) or d3 = d1.copy(); d3.update(d2) — values from d2 overwrite d1 on key conflict.
🧮 Formulas
  1. \[len(d) -> number of key:value pairs\]
  2. \[key in d -> True/False (checks presence of key)\]
  3. \[d[key] = value -> insert or update the key with value\]
  4. \[value = d.get(key\]
    \[default) -> safe access without KeyError\]
  5. \[del d[key] or d.pop(key) -> remove a key and its value\]
  6. \[d.keys()\]
    \[d.values()\]
    \[d.items() -> views for keys\]
    \[values\]
    \[pairs\]
⚖️11

Sequence Operations, Indexing and Slicing

💻 COMPUTER SCIENCE / IT

Sequence Operations, Indexing and Slicing

Key Point: Indexing: element at position i is seq[i] where i in 0..len(seq)-1; negative index: seq[-k] == seq[len(seq)-k]

Overview: In Python a sequence is an ordered collection of items. Common sequence types are strings, lists and tuples. Sequences support indexing (accessing single elements), slicing (extracting subsequences), and several operations such as concatenation, repetition and membership tests.

Indexing

  • Indices are zero-based: the first element has index 0, the second index 1, and so on. Example: seq[0] is the first element.
  • Negative indices access elements from the end: seq[-1] is the last element, seq[-2] is the second last, etc. Formula: seq[-k] == seq[len(seq) - k].
  • Attempting to use an index outside the valid range raises IndexError for lists/tuples/strings.

Slicing

  • General form: seq[start:stop:step]. The slice returns a new sequence of the same type (for strings, lists, tuples) containing elements from index start up to but not including stop, taken every step positions.
  • Defaults: if start is omitted it defaults to 0 (when step > 0). If stop is omitted it defaults to len(seq). If step is omitted it defaults to 1.
  • Negative step reverses direction: seq[::-1] returns the sequence reversed. With a negative step, default start becomes len(seq)-1 and default stop becomes -1 (stop excluded).
  • Slices always produce a new object (a shallow copy for lists). For immutable sequences like strings and tuples you cannot modify elements; for lists you can assign to a slice to change multiple elements at once, e.g. lst[1:3] = [x, y].

Common sequence operations

  • Concatenation: seq1 + seq2 joins two sequences of the same type (strings or lists or tuples).
  • Repetition: seq * n repeats the sequence n times.
  • Membership: x in seq returns True if x appears in seq.
  • Length and extrema: len(seq), min(seq), max(seq) (when elements are comparable).
  • Iteration: for loops iterate elements in order: for item in seq:

Practical notes and pitfalls

  • Remember that slicing stop index is exclusive: seq[1:4] returns elements at indices 1,2,3.
  • Using an out-of-range index for slicing does not raise an error; Python clamps the indices to valid range. But direct indexing with an out-of-range index raises IndexError.
  • Because slicing returns a new object, modifying the returned slice does not change the original sequence (except by assigning back to a slice of a mutable sequence).

Short code summary

s = 'python'
# indexing
s[0]     # 'p'
s[-1]    # 'n'
# slicing
s[1:4]   # 'yth'  (indices 1,2,3)
s[:3]    # 'pyt'
s[3:]    # 'hon'
s[::2]   # 'pto'  (every second char)
s[::-1]  # 'nohtyp' (reversed)

lst = [10,20,30,40,50]
lst[1:4]         # [20,30,40]
lst[1:4:2]       # [20,40]
lst[-3:-1]       # [30,40]
lst + [60,70]    # [10,20,30,40,50,60,70]
lst * 2          # [10,20,30,40,50,10,20,30,40,50]
📌 Examples
  • Example 1 - Days of week: days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] - days[0] -> 'Mon' - days[-1] -> 'Sun' - days[1:5] -> ['Tue','Wed','Thu','Fri'] (slices exclude stop index) - days[::2] -> ['Mon','Wed','Fri','Sun'] (every second day)
  • Example 2 - Top marks: marks = [72, 85, 90, 65, 88, 91] - sorted marks then take top 3 using slicing: sorted_marks = sorted(marks) - top3 = sorted_marks[-3:] -> last three elements are top scorers
  • Example 3 - Extracting every nth sensor reading: readings = [r0, r1, r2, ...] - sample_every_5 = readings[::5] returns readings at indices 0,5,10,...
  • Example 4 - Reverse a string: name = 'RAHUL' - name[::-1] -> 'LUHAR' (useful for palindromes and reversing sequences)
🧮 Formulas
  1. \[Indexing: element at position i is seq[i] where i in 0..len(seq)-1\]
    \[negative index: seq[-k] == seq[len(seq)-k]\]
  2. \[Slicing syntax: seq[start:stop:step] returns indices start\]
    \[start+step\]
    \[start+2*step, ... up to but not including stop\]
  3. \[Default values: if start omitted -> 0 (when step>0)\]
    \[if stop omitted -> len(seq)\]
    \[if step omitted -> 1\]
  4. \[Number of items in slice (step>0): count = max(0\]
    \[((stop - start + step - 1) // step)) (indices treated after clamping to valid range)\]
💻12

Mutability, Immutability and Aliasing

💻 COMPUTER SCIENCE / IT

Mutability, Immutability and Aliasing

Key Point: Aliasing condition: name1 is name2 => both names refer to the same object (same id).

Overview

In Python, every value is an object. Objects are either mutable (their content can change after creation) or immutable (their content cannot change; any operation that looks like a change actually creates a new object). Aliasing happens when two or more names (variables) refer to the same object in memory.

Why this matters

  • Mutability affects program behaviour: modifying a mutable object through one name affects all names that refer to it.
  • Immutability gives safety and predictability: you cannot accidentally change an object shared elsewhere.
  • Aliasing can cause bugs if you unintentionally share and then mutate objects.

Mutable vs Immutable (common Python types)

  • Mutable: list, dict, set, bytearray, most custom objects (unless designed otherwise)
  • Immutable: int, float, bool, str, tuple, frozenset, bytes

Identity vs Equality

  • Equality (==) checks whether values are equal.
  • Identity (is) checks whether two names point to the same object (same memory address).
  • id(x) returns the unique identity (address) of object x while it exists.

Typical behaviours

  • Assigning a name to an object just creates a reference (no copy). Example: a = [1, 2]; b = a — both a and b reference the same list.
  • Mutating methods change the object in-place: append, extend, pop, clear, dictionary updates, etc.
  • Operations on immutables produce new objects. For strings and tuples, operations that appear to change them actually bind the name to a new object.

Shallow vs Deep Copy

  • Shallow copy copies the container but keeps references to the same elements (use list.copy(), slicing [:], or copy.copy()).
  • Deep copy recursively copies nested objects so no shared sub-objects remain (use copy.deepcopy()).

Practical advice

  • When you need independent objects, explicitly copy (shallow or deep) instead of relying on assignment.
  • Use immutable objects for keys in dictionaries (e.g., tuple but not list).
  • Use is only to check identity (such as None checks); use == for value equality.

Short code demonstrations

# Mutable aliasing example
a = [1, 2]
b = a    # b aliases the same list as a
b.append(3)
print(a)  # Output: [1, 2, 3]
print(a is b)  # True (same object)

# Immutable behavior
s1 = 'hi'
s2 = s1
s2 += '!'  # creates a new string and binds s2 to it
print(s1)  # 'hi'
print(s2)  # 'hi!'
print(s1 is s2)  # Usually False

# Shallow vs deep copy
import copy
orig = [[1], [2]]
sh = orig.copy()          # shallow copy
dp = copy.deepcopy(orig) # deep copy
sh[0].append(99)
print(orig)  # [[1, 99], [2]]  (inner list shared with shallow copy)
print(dp)    # [[1], [2]]    (deep copy unaffected)
📌 Examples
  • Real-life analogy: A printed flyer (immutable) vs. a whiteboard (mutable). If two people each hold a copy of a flyer, changing one person's flyer doesn’t change the other's. If two people point to the same whiteboard and one erases something, both see the change (aliasing).
  • Python list aliasing: a = [10]; b = a; b.append(20) => a becomes [10, 20] because a and b reference the same mutable list.
  • Python string immutability: s = 'cat'; t = s; t += 's' => s stays 'cat', t becomes 'cats' because concatenation creates a new string.
  • Shallow copy problem: nested = [[1],[2]]; s = nested[:] ; s[0].append(9) changes nested too — inner lists are shared.
  • Avoiding aliasing: make copies when needed: copy_list = original_list.copy() or import copy; safe = copy.deepcopy(original_nested_structure).
🧮 Formulas
  1. \[Aliasing condition: name1 is name2 => both names refer to the same object (same id).\]
  2. \[Identity test: id(a) == id(b) <=> a is b\]
  3. \[Mutating operation: mut_obj.mutate(...) modifies the same object in-place\]
    \[no new id assigned.\]
  4. \[Immutable operation: imm_obj + something returns a new object\]
    \[id(imm_obj) typically changes after reassignment.\]
  5. \[Shallow copy: new_container refers to the same elements as old_container (copy only top-level container).\]
  6. \[Deep copy: new_container has independent copies of nested elements (no shared sub-objects).\]
⚖️13

Traversal and Iteration

💻 COMPUTER SCIENCE / IT

Traversal and Iteration

Key Point: Accumulator pattern (sum): total = 0; for x in A: total = total + x => average = total / len(A)

What is Traversal?
Traversal is the process of visiting each element of a data structure (like a list, tuple, string, set, dictionary or a 2‑D list) so you can read or process the elements. Example uses: counting, searching, summing, filtering.

What is Iteration?
Iteration is the repeated execution of a block of code. In Python iteration is usually done with loops (for, while) or by using iterators and generator objects. When you iterate over an iterable (like a list), the loop visits elements one by one — this is traversal implemented by iteration.

Difference (brief):
Traversal is the goal (visit all elements). Iteration is the mechanism (repeating steps using loops or iterators).

Common iteration constructs in Python

  • for loop: used to repeat a block for each element in an iterable.
  • while loop: repeats while a condition holds; useful when number of steps is not known beforehand.
  • Iterator protocol: objects implement __iter__() and __next__() so they can be used by for and next().
  • Generator expressions and functions: produce values on the fly (memory efficient).

Useful built‑ins and idioms

  • range(n) — sequence of integers 0..n-1, commonly used to get indices.
  • enumerate(iterable) — gives (index, value) pairs while looping.
  • zip(a, b) — iterate two sequences in parallel.
  • items(), keys(), values() — iterate over dictionary entries.
  • List comprehensions — concise way to build lists by iterating and optionally filtering.

Controlling iteration: break (exit loop), continue (skip to next iteration), and pass (do nothing).

Examples of traversal patterns

  • Simple linear traversal: visiting all elements of a list.
  • Indexed traversal: using indices to access or modify elements.
  • Nested traversal: traversing a 2‑D list or matrix using nested loops.
  • Conditional traversal: visit elements that meet a condition (filtering).

Iterator protocol (short)
An object is iterable if it implements __iter__() returning an iterator. An iterator implements __next__() which returns next value or raises StopIteration.

Good practices

  • Prefer for loops over manual index loops when possible (safer, more Pythonic).
  • Use enumerate() instead of maintaining a separate index counter.
  • Avoid modifying a list while traversing it — iterate over a copy (list[:] ) if you must change the original.
  • Use generators for large data to save memory.

Short code examples

# Linear traversal
numbers = [10, 20, 30]
for n in numbers:
    print(n)

# Using enumerate to get index and value
for i, val in enumerate(numbers):
    print(i, val)

# Traversing a matrix (2D list)
matrix = [[1,2,3],[4,5,6]]
for i in range(len(matrix)):
    for j in range(len(matrix[0])):
        print('element at', i, j, 'is', matrix[i][j])

# Using a generator (memory efficient)
def gen_squares(n):
    for i in range(n):
        yield i*i
for sq in gen_squares(5):
    print(sq)

When traversal and iteration matter
For tasks such as searching (linear scan), aggregation (sum, max, average), filtering (select elements that match a condition), transforming (map each element), and combining sequences (zip) — traversal + iteration are the core techniques.

📌 Examples
  • Class register: Traverse a list of student names to mark attendance. Code idea: for name in students: mark_attendance(name).
  • Calculate total marks: Traverse the marks list, accumulate sum using an accumulator variable. total = 0; for m in marks: total += m
  • Find highest score: Iterate through scores and update max_so_far when a larger score is found.
  • Matrix traversal: For a seating plan (2D list), use nested loops to print seat numbers or check empty seats.
  • Filtering: From a list of ages, create a new list of adults using list comprehension: adults = [a for a in ages if a >= 18]
  • Parallel iteration: Combine roll numbers and names using zip: for r, n in zip(rolls, names): print(r, n)
🧮 Formulas
  1. \[Accumulator pattern (sum): total = 0\]
    \[for x in A: total = total + x => average = total / len(A)\]
  2. \[Count occurrences: count = 0\]
    \[for x in A: if predicate(x): count += 1\]
  3. \[Linear search steps: in worst case\]
    \[comparisons = n (for n elements) — O(n) time\]
  4. \[Nested loops (matrix of size n×m): operations ≈ n * m — O(n*m)\]
    \[for two nested loops over n elements each: O(n^2)\]
  5. \[Index mapping for 2D to 1D (row-major): index = i * num_cols + j (useful for visual layouts)\]
🧬14

Comprehensions and Generator Expressions

💻 COMPUTER SCIENCE / IT

Comprehensions and Generator Expressions

Key Point: General patterns: - List: [expression for item in iterable if condition] - Set: {expression for item in iterable if condition} - Dict: {key_expr: value_expr for item in iterable if condition} - Generator: (expression for item in iterable if condition)

Overview: Comprehensions and generator expressions are concise, readable ways to create new sequences or iterators from existing iterables using a compact syntax. They replace many simple for-loops and make transformations and filtering easy to express.

Types and basic syntax:

  • List comprehension: [expression for item in iterable if condition]
  • Set comprehension: {expression for item in iterable if condition}
  • Dictionary comprehension: {key_expr: value_expr for item in iterable if condition}
  • Generator expression: (expression for item in iterable if condition)

How they work:

- A comprehension evaluates the expression for each item in the input iterable and collects the results into a new container (list, set, dict). This builds the entire result in memory.

- A generator expression produces values on demand (lazy evaluation). It returns a generator object and yields items one by one as you iterate, so it uses far less memory for large streams.

Examples (short):

# List of squares
squares = [x*x for x in range(10)]

# Filtered list: even numbers
evens = [x for x in range(20) if x % 2 == 0]

# Dict: number -> square
sq_map = {x: x*x for x in range(6)}

# Set: unique word lengths from a sentence
words = 'this is a sample sentence'.split()
lengths = {len(w) for w in words}

# Generator: lazy squares for large range
gen = (x*x for x in range(10**7))  # no list created

Key behavioral notes:

  • Comprehensions evaluate immediately and return a concrete container; generator expressions are lazy and return an iterator.
  • Generator expressions can be passed directly to functions that consume iterables (e.g., sum(), any(), max()).
  • Generators are exhausted after iteration; to reuse results you must recreate them or store the results.
  • Comprehensions are generally as fast as equivalent for-loops (often faster in CPython) and usually clearer, but overly complex nested comprehensions hurt readability.

Nesting:

# Flatten a matrix
matrix = [[1,2,3],[4,5],[6]]
flat = [elem for row in matrix for elem in row]

# Nested comprehension with condition
pairs = [(i,j) for i in range(3) for j in range(3) if i != j]

Real-life use cases:

  • Transforming CSV rows into dicts: [dict(zip(headers,row)) for row in rows]
  • Filtering sensor readings: [r for r in readings if r.value > threshold]
  • Streaming large log files and counting matches with a generator: sum(1 for line in open('log') if 'ERROR' in line)

Pitfalls & tips:

  • Do not use huge list comprehensions when a generator can do the job (memory pressure).
  • Prefer comprehensions for simple transformations; use functions or loops if logic is complex for readability.
  • Remember that dict comprehensions require unique keys; later keys overwrite earlier ones.

Summary: Use list/set/dict comprehensions when you need a concrete container produced immediately. Use generator expressions when you want lazy evaluation, reduced memory usage, or to feed an iterable-consuming function.

📌 Examples
  • List comprehension — squares: squares = [x*x for x in range(10)] # result: [0,1,4,9,...,81]
  • Filtered list — evens: evens = [x for x in range(20) if x % 2 == 0] # keeps only even numbers
  • Dict comprehension — mapping: sq_map = {x: x*x for x in range(6)} # {0:0, 1:1, 2:4, ...}
  • Set comprehension — unique lengths: lengths = {len(w) for w in 'this is a sample'.split()} # {1,2,4,6}
  • Nested list comprehension — flatten matrix: flat = [e for row in matrix for e in row] # flattens nested lists
  • Generator expression — memory efficient: gen = (x*x for x in range(10**7)); next(gen) # yields values on demand
🧮 Formulas
  1. \[General patterns: - List: [expression for item in iterable if condition] - Set: {expression for item in iterable if condition} - Dict: {key_expr: value_expr for item in iterable if condition} - Generator: (expression for item in iterable if condition)\]
  2. \[Complexity and memory (big-O): - Time: O(n) to process n items (same as an explicit loop) - Memory: list/set/dict comprehension => O(n) (stores all results) - Generator expression => O(1) extra memory (yields one item at a time\]
    \[ignoring the memory of items consumed)\]
  3. \[Memory comparison (conceptual): - list_size ≈ n * average_item_size - generator_peak ≈ constant_overhead + size_of_current_item\]
💻15

Built‑in Functions and Useful Modules

📐 MATHEMATICAL FORMULA / THEOREM

Built‑in Functions and Useful Modules

Key Point: Mean (arithmetic average): mean = (x1 + x2 + ... + xn) / n — Python: statistics.mean(list)

Overview
Built‑in functions are pre-defined functions available in Python without importing anything (for example: len(), sum(), min()). Useful modules are collections of related functions and classes grouped in standard libraries that you import (for example: math, random, statistics, datetime).

Why they matter
They let you perform common tasks quickly and correctly: numerical operations, statistical summaries, date/time handling, random sampling, file & data handling. Using them avoids reinventing the wheel and makes code shorter and more reliable.

Common built‑in functions (short descriptions)

  • len(obj) — length of sequence or collection.
  • type(x) — type of an object.
  • int(), float(), str() — type conversions.
  • sum(iterable), min(), max(), round(), abs().
  • sorted(iterable), reversed().
  • map(func, iterable), filter(func, iterable), zip(), enumerate().
  • any(), all() — boolean checks across iterables.
  • divmod(a,b), pow(a,b).
  • help(obj), dir(obj), isinstance(obj, Type) — introspection and debugging.

How to use modules
Import a module to access its functions. Example forms: import math, from math import sqrt, pi, import datetime as dt.

Key useful modules (class 11 focus)

  • math — mathematical functions: sqrt(), factorial(), sin/cos, pi, etc.
  • random — random numbers and choices: randint(), choice(), shuffle().
  • statistics — mean, median, mode, variance, stdev: mean(), median().
  • datetime — dates and times: datetime.now(), date arithmetic.
  • json — read/write JSON data (json.load(), json.dump()).
  • os, sys — file and system operations (optional for basic data tasks).

Small code examples

# statistics: mean, median
from statistics import mean, median
marks = [78, 82, 91, 67, 88]
print('Mean=', mean(marks))
print('Median=', median(marks))

# math: factorial and square root
import math
print('5! =', math.factorial(5))
print('sqrt(25)=', math.sqrt(25))

# random: simple sampling
import random
students = ['A', 'B', 'C', 'D']
print('Random pick:', random.choice(students))

# datetime: difference between dates
from datetime import date
d1 = date(2025, 1, 1)
d2 = date(2025, 10, 11)
print('Days between =', (d2 - d1).days)

# map and filter
nums = [1, 2, 3, 4]
sq = list(map(lambda x: x*x, nums))
even = list(filter(lambda x: x%2==0, nums))
print(sq, even)

Best practices

  • Prefer standard library functions (they are tested and efficient).
  • Import only what you need: from module import func or alias with as.
  • Use help() and dir() to explore unfamiliar modules.

Class 11 focus
Understand how to call built‑ins, use map/filter/zip/enumerate with lists, and use the listed modules for solving common data problems: computing statistics, generating random samples, and handling dates.

📌 Examples
  • Compute class test statistics: use statistics.mean(marks), statistics.median(marks), statistics.pstdev/variance to report class performance. Example code: from statistics import mean, median; marks=[78,82,91,67,88]; print(mean(marks), median(marks))
  • Generating lottery-style random numbers: import random; nums = random.sample(range(1,50), 6) — picks 6 unique numbers from 1–49.
  • Attendance percentage and pass/fail quick check: present = 160; total = 200; percent = (present/total)*100; status = 'Pass' if percent>=75 else 'Fail'. Use round(percent,1) to format.
  • Reading and writing simple JSON data (student record): import json; data={'name':'Ria','marks':[85,90]}; json.dump(data, open('rec.json','w')) and later json.load(open('rec.json'))
  • Date difference for event planning: from datetime import date; days_left = (event_date - date.today()).days to show days remaining.
🧮 Formulas
  1. \[Mean (arithmetic average): mean = (x1 + x2 + ... + xn) / n — Python: statistics.mean(list)\]
  2. \[Median: middle value when sorted (or average of two middles) — Python: statistics.median(list)\]
  3. \[Mode: most frequent value — Python: statistics.mode(list)\]
  4. \[Population variance: σ² = (Σ(xi - μ)²) / n — Python: statistics.pvariance(list) or statistics.variance(list) for sample\]
  5. \[Standard deviation: σ = sqrt(variance) — Python: statistics.pstdev(list) or statistics.stdev(list)\]
  6. \[Compound formulas using math: e.g.\]
    \[quadratic roots = (-b ± sqrt(b^2-4ac)) / (2a) — use math.sqrt and arithmetic operators\]
📊16

CRUD Operations on Data Structures

💻 COMPUTER SCIENCE / IT

CRUD Operations on Data Structures

Key Point: List: append(element) — Create (amortized O(1)); index access list[i] — Read O(1); insert(i, x) — Update/insert O(n); remove(x) / pop(i) — Delete O(n) (pop() at end O(1)).

CRUD stands for Create, Read, Update and Delete — the four basic operations you perform on data. In Python these operations are carried out on built-in data structures (lists, tuples, sets, dictionaries, strings) using specific methods or operators. Understanding how CRUD maps to each data structure helps you choose the right structure and write efficient code.

Create: make a new container or add new items. Examples: list append/extend, dict assignment, set add.

Read: access elements without changing them. Examples: indexing, slicing, iteration, dict.get, membership (in).

Update: change existing elements or replace containers. Examples: assignment to list index, list insert, dict[key] = value, set operations (union), note that tuples and strings are immutable so you create a new object instead of modifying in place.

Delete: remove elements or entire containers. Examples: del, pop, remove, clear, dict.pop, set.discard.

Mutability notes: Lists, dictionaries and sets are mutable (support in-place update/delete). Tuples and strings are immutable (you must create a new tuple/string when "updating").

Common pitfalls & good practices:

  • Use dicts for key-based CRUD (fast average lookup/change).
  • For ordered collections use lists; insertion/removal in middle is O(n).
  • Check for membership with in before removing to avoid exceptions or use methods like discard for sets.
  • Prefer dict.get(key, default) to avoid KeyError when reading.

Small code examples:

# List (mutable)
items = [10, 20]
# Create
items.append(30)
# Read
x = items[1]        # 20
# Update
items[0] = 15
# Delete
items.remove(20)

# Dictionary (mutable, key-based)
students = {'A001': 'Rita'}
# Create / Update
students['A002'] = 'Vikram'
students['A001'] = 'Rita Sharma'  # update
# Read
name = students.get('A001')
# Delete
students.pop('A002', None)

# Tuple (immutable)
t = (1, 2)
# To "update" create a new tuple
t = t + (3,)

# Set (mutable, unique elements)
s = {2, 3}
s.add(4)
if 3 in s:
    s.remove(3)

By mapping CRUD to appropriate Python methods and being aware of time/space costs, you can design simple data-driven programs (contact lists, inventories, student records) efficiently and safely.

📌 Examples
  • Contact list (dictionary): Use dict where key = phone/email and value = contact info. Create: contacts['raj@example.com'] = {'name':'Raj','phone':9876}. Read: contacts.get('raj@example.com'). Update: contacts['raj@example.com']['phone']=9999. Delete: contacts.pop('raj@example.com', None).
  • Shopping cart (list of dicts): Each cart item is a dict; Create: cart.append({'id':101,'qty':1}). Read: iterate for display. Update: increase qty by modifying the dict in the list. Delete: cart.pop(index) or remove item with matching id.
  • Student marks (list + dict): Store students as list of dicts or dict of dicts keyed by roll number. Use dict for fast read/update by roll no. Create: students['S01']={'name':'Anu','marks':85}. Read: students['S01']['marks']. Update: students['S01']['marks']=90. Delete: del students['S01'].
  • Inventory system (set for SKUs): Use set to store unique product codes. Create: skus.add('P100'); Read: 'P100' in skus; Delete: skus.discard('P100').
🧮 Formulas
  1. \[List: append(element) — Create (amortized O(1))\]
    \[index access list[i] — Read O(1)\]
    \[insert(i\]
    \[x) — Update/insert O(n)\]
    \[remove(x) / pop(i) — Delete O(n) (pop() at end O(1)).\]
  2. \[Dictionary: dict[key] = value — Create/Update average O(1)\]
    \[dict.get(key) — Read average O(1)\]
    \[del dict[key] / dict.pop(key) — Delete average O(1).\]
  3. \[Set: add(x) — Create average O(1)\]
    \[x in set — Read membership average O(1)\]
    \[remove(x)/discard(x) — Delete average O(1).\]
  4. \[Tuple & String: immutable — 'Update' costs creating a new object (O(n) to copy).\]
  5. \[Useful method signatures: list.append(x)\]
    \[list.insert(i,x)\]
    \[list.pop(i)\]
    \[list.remove(x)\]
    \[dict.get(k\]
    \[default)\]
    \[dict.keys()\]
    \[dict.values()\]
    \[dict.pop(k\]
    \[default)\]
    \[set.add(x)\]
    \[set.remove(x)\]
    \[set.discard(x)\]
    \[set.pop().\]
📊17

Conversion Between Data Structures

💻 COMPUTER SCIENCE / IT

Conversion Between Data Structures

Key Point: list(iterable) -> list of elements in iterable (order preserved for sequences).

What it is: Conversion between data structures in Python means transforming data from one built-in container type to another (list, tuple, set, dict, string) using constructors or methods so that the data can be used in an appropriate way (mutable/immutable, ordered/unordered, unique elements, key-value access).

Why it matters: Different tasks require different properties: lists for ordered mutable sequences, tuples for fixed records, sets for uniqueness and fast membership tests, and dictionaries for lookup by keys. Converting lets you use the best structure for each task.

Basic rules and behavior:

  • list(iterable) — creates a list preserving order of the iterable.
  • tuple(iterable) — creates an immutable tuple from the iterable.
  • set(iterable) — creates an unordered collection with duplicates removed; order not guaranteed.
  • dict(...) — constructs dictionaries. Passing a mapping or an iterable of key-value pairs (e.g., list of tuples) produces a dict. Passing just an iterable (like list of keys) does not by itself form key-value pairs.
  • str.join(list_of_strings) and str.split(...) — convert between strings and lists of substrings.

Important consequences:

  • Converting to set removes duplicates — use to get unique items (but original order is not preserved).
  • Converting a dict to list returns a list of keys. Use dict.items() to get (key, value) pairs and dict.values() for values.
  • Converting a list of two-item tuples to dict maps each first item to the second; duplicate keys get overwritten by the last occurrence.
  • Mutability: converting to tuple makes data immutable; converting from tuple to list allows modification.

Complexities (brief): Most conversions are O(n) where n is the number of elements because each element must be visited.

Typical conversion functions and patterns:

# Examples of constructors and methods used for conversion
list(some_iterable)      # to list
tuple(some_iterable)     # to tuple
set(some_iterable)       # to set (unique elements)
str.join(list_of_strings)  # to string
some_string.split(sep)   # to list of substrings
dict(list_of_pairs)      # from [(key, value), ...]
list(a_dict)             # list of dict keys
list(a_dict.items())     # list of (key, value) tuples
list(a_dict.values())    # list of values
zip(keys, values)        # pairs two iterables; often wrapped with dict()
📌 Examples
  • Example 1 — Remove duplicates from a list (order not guaranteed): input_list = [2, 3, 2, 5, 3] unique_set = set(input_list) # {2, 3, 5} unique_list = list(unique_set) # [2, 3, 5] (order may vary)
  • Example 2 — Convert string to list and back: s = 'apple,banana,cherry' fruits = s.split(',') # ['apple', 'banana', 'cherry'] new_s = ';'.join(fruits) # 'apple;banana;cherry'
  • Example 3 — Convert list of tuples to dictionary (pairs): pairs = [('a', 1), ('b', 2), ('c', 3)] D = dict(pairs) # {'a': 1, 'b': 2, 'c': 3} # If duplicate keys exist, last value wins: dict([('a',1),('a',9)]) -> {'a': 9}
  • Example 4 — Get keys, values, items from dict: D = {'r1': 90, 'r2': 85} keys = list(D) # ['r1', 'r2'] values = list(D.values()) # [90, 85] items = list(D.items()) # [('r1', 90), ('r2', 85)]
  • Example 5 — Convert tuple to list to modify, then back: coords = (10, 20) coords_list = list(coords) coords_list[0] = 15 coords = tuple(coords_list) # (15, 20)
🧮 Formulas
  1. \[list(iterable) -> list of elements in iterable (order preserved for sequences).\]
  2. \[tuple(iterable) -> tuple with same elements (immutable).\]
  3. \[set(iterable) -> set of unique elements (duplicates removed\]
    \[order not guaranteed).\]
  4. \[dict(iterable_of_pairs) -> dictionary mapping first->second for each (key\]
    \[value) pair.\]
  5. \[str.split(sep) -> list of substrings\]
    \[sep.join(list_of_strings) -> single string.\]
  6. \[list(a_dict) -> list of keys\]
    \[list(a_dict.items()) -> list of (key\]
    \[value) tuples\]
    \[list(a_dict.values()) -> list of values.\]
📊18

Nested Data Structures

💻 COMPUTER SCIENCE / IT

Nested Data Structures

Key Point: Access notation: nested_list[i][j] or nested_dict['key1']['key2'] — chain indices/keys from outer to inner.

What are Nested Data Structures?

Nested data structures are data structures that contain other data structures as their elements. In Python this typically means lists, tuples, sets or dictionaries can hold other lists, tuples, sets or dictionaries. Nesting lets you represent complex, hierarchical data (tables, trees, JSON-like records) naturally.

Common nested types

  • List of lists (2D lists): a matrix or table representation.
  • List of dictionaries: a collection of records (e.g., list of student records).
  • Dictionary of lists: grouped properties under keys (e.g., subjects -> marks list).
  • Dictionary of dictionaries: hierarchical keyed data (e.g., JSON objects).
  • Tuples inside lists or vice-versa: fixed-size records inside a mutable collection.

How to access elements

Accessing nested elements is done by chaining index or key operations. Examples:

# 2D list: matrix[i][j]
matrix = [[1,2],[3,4]]
val = matrix[0][1]  # 2

# nested dict: d['a']['b']
d = {'a': {'b': 10}}
val = d['a']['b']  # 10

# list of dicts: students[0]['name']
students = [{'name': 'Alice', 'age': 15}, {'name': 'Bob', 'age': 16}]
name0 = students[0]['name']  # 'Alice'

Iteration and nested loops

To process nested structures, use nested loops or nested comprehensions. For example, iterating a 2D list uses one loop per dimension:

for row in matrix:
    for item in row:
        print(item)

# Nested comprehension to flatten a 2D list
flat = [item for row in matrix for item in row]

Modification and mutability

Be aware of mutability: lists and dictionaries are mutable; tuples are not. If you store a mutable object (like a list) inside multiple places, modifying it in one place affects all references. Use copy.copy or copy.deepcopy when needed.

Common operations and cautions

  • Flattening: convert nested lists into a single list (via nested loops or comprehensions).
  • Depth (nesting level): keep track to avoid deep recursion; Python has recursion limits.
  • Shallow vs deep copy: shallow copy copies references to inner objects; deep copy duplicates nested contents.
  • Performance: nested loops increase time complexity multiplicatively (see formulas below).

Real-life use-cases

  • Spreadsheet data: 2D lists for rows and columns.
  • JSON APIs: dictionaries with nested dictionaries and lists for structured responses (users → posts → comments).
  • School records: list of dicts where each dict stores name, grades (list), and address (dict).
  • Graphs and trees: adjacency lists (dict of lists) or nested dicts for nodes and properties.
📌 Examples
  • Nested list (2D list / matrix): matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # access element in row 2, column 3 (0-based): matrix[1][2] -> 6
  • List of dictionaries (records): students = [ {'name': 'Alice', 'age': 15, 'marks': [85, 92]}, {'name': 'Bob', 'age': 16, 'marks': [78, 81]} ] # get Bob's second mark: students[1]['marks'][1] # 81
  • Dictionary of dictionaries (nested mapping): school = { 'Class10': {'teacher': 'Mr Rao', 'students': 32}, 'Class11': {'teacher': 'Ms Iyer', 'students': 28} } # teacher of Class11: school['Class11']['teacher'] # 'Ms Iyer'
  • Nested comprehension (flatten 2D list): flat = [item for row in matrix for item in row] # flat -> [1,2,3,4,5,6,7,8,9]
  • Deep copy vs shallow copy example: import copy outer = [[1,2], [3,4]] sh = outer.copy() # shallow copy: inner lists are same objects sh[0][0] = 99 # outer is now [[99,2],[3,4]] outer = [[1,2],[3,4]] dp = copy.deepcopy(outer) # deep copy: inner lists are independent
🧮 Formulas
  1. \[Access notation: nested_list[i][j] or nested_dict['key1']['key2'] — chain indices/keys from outer to inner.\]
  2. \[Length relation: total_items = sum(len(sub) for sub in outer_list) # for list of lists\]
  3. \[Time complexity for basic ops: - Indexing into list by index: O(1) - Access by key in dict: average O(1) - Iterating nested lists: O(product_of_dimensions) e.g., 2D list with n*m elements is O(n*m) - Searching through nested structure by value: O(total elements)\]
  4. \[Nested loops complexity: if outer has n items and each inner has m items\]
    \[nested loops cost O(n * m).\]
  5. \[Flattening cost: O(total_elements) where total_elements = sum of lengths of all sub-containers.\]
  6. \[Shallow copy vs deep copy: - shallow_copy = container.copy() # copies outer container\]
    \[inner references shared - deep_copy = copy.deepcopy(container) # duplicates nested contents\]
📊19

Error Handling Related to Data Operations

💻 COMPUTER SCIENCE / IT

Error Handling Related to Data Operations

Key Point: try -> except : -> (optional) else -> (optional) finally (pattern for handling exceptions and cleanup)

What it is: Error handling related to data operations means writing Python code that anticipates, detects and responds to errors that occur when reading, writing, converting, or validating data (files, user input, CSV/JSON, lists/dicts, etc.). Good error handling keeps programs robust, prevents crashes, and makes failures informative.

Why it matters: Data is often messy or unavailable: files may be missing, numbers may be malformed, fields may be missing, or external resources may be temporarily unreachable. Without handling these situations a program will raise exceptions and stop. Proper handling lets you give defaults, retry, log problems, or fail gracefully.

Common exception types in data operations

  • FileNotFoundError / IOError: file missing or unreadable.
  • ValueError: converting a string to int/float fails (e.g., int("abc")).
  • TypeError: operation applied to wrong type (e.g., adding str and int).
  • IndexError: accessing invalid list index.
  • KeyError: missing key in a dictionary.
  • ZeroDivisionError: division by zero when computing statistics.
  • json.JSONDecodeError / UnicodeDecodeError: malformed JSON or wrong file encoding.

Techniques and patterns

  • Use try/except to catch specific exceptions and handle them. Prefer catching specific exception classes rather than a bare except:.
  • Use else to run code when no exception occurred, and finally to always run cleanup (close resources) if not using with.
  • Use with open(...) to ensure files are closed automatically.
  • Validate and sanitize input before converting: strip whitespace, check numeric pattern, or use helper functions that return defaults on failure.
  • Raise meaningful exceptions with raise ValueError('message') when detecting invalid data inside functions (fail fast).
  • Log errors (using the logging module) so the cause can be diagnosed later rather than silently ignoring problems.
  • Provide fallbacks or retry logic for transient errors (e.g., network read). Keep retries limited and use backoff if needed.

Best practices

  • Catch the narrowest exception you expect.
  • Keep try blocks small — only include the statement(s) that might raise the expected error.
  • Don’t use exceptions for normal control flow.
  • Provide clear error messages and use logging for diagnostics.
  • Validate input and data formats before processing.

Short code patterns

# safe file open with fallback
try:
    with open('data.csv') as f:
        text = f.read()
except FileNotFoundError:
    print('data.csv not found — using default data')
    text = ''

# safe conversion with default
try:
    x = int(user_input)
except ValueError:
    x = 0  # fallback or ask again

# raise when encountering invalid record
def parse_age(s):
    try:
        age = int(s)
    except ValueError:
        raise ValueError(f'Invalid age: {s}')
    if age < 0:
        raise ValueError('Age must be >= 0')
    return age

In sum: anticipate likely problems from external or untrusted data, catch and handle specific exceptions, validate input early, and ensure resources are always cleaned up.

📌 Examples
  • Reading a student marks file where the file may not exist: try: with open('marks.csv') as f: lines = f.readlines() except FileNotFoundError: print('marks.csv not found — please provide the file') lines = []
  • Converting CSV fields to numbers while skipping malformed entries: safe_marks = [] for token in row: try: m = float(token) except ValueError: # log and skip bad value print(f'Bad number: {token} — treated as 0') m = 0.0 safe_marks.append(m)
  • Preventing crash on division by zero when computing average: try: avg = total / count except ZeroDivisionError: avg = 0 # or handle as 'no data' # better: check before dividing if count == 0: avg = 0 else: avg = total / count
  • Accessing dictionary keys safely (KeyError): student = {'name': 'Anita', 'marks': 78} marks = student.get('marks', 0) # returns 0 if key missing # or try: email = student['email'] except KeyError: email = 'not provided'
🧮 Formulas
  1. \[try -> except <ExceptionType>: -> (optional) else -> (optional) finally (pattern for handling exceptions and cleanup)\]
  2. \[with open(filename\]
    \[mode) as f: (automatic resource management\]
    \[avoids needing finally to close file)\]
  3. \[int(s) # may raise ValueError if s is not numeric\]
    \[use try/except to catch\]
  4. \[raise ValueError('message') # to signal invalid data from inside a function\]
  5. \[dict.get(key\]
    \[default) # safe access to dictionary values without KeyError\]
💻20

Practical Examples and Problem Solving

💻 COMPUTER SCIENCE / IT

Practical Examples and Problem Solving

Key Point: Mean (average): mean = sum(x_i) / n Python: mean = sum(values)/len(values)

'Practical Examples and Problem Solving' in the 'Working with Data in Python' chapter teaches how to apply Python to collect, clean, analyze and present data to solve real-world problems. The process follows these steps:

  • Understand the problem: identify inputs, outputs and constraints.
  • Choose data structures: lists, tuples, dictionaries, sets for different needs (ordered data, key-value lookup, unique elements).
  • Data ingestion: read data from user input, text files or CSV (use the csv module or pandas for larger tasks).
  • Data cleaning & validation: handle missing values, convert types (strings to int/float), strip whitespace.
  • Processing & algorithms: counting, searching, filtering, sorting, aggregations (sum, mean, median), grouping by keys.
  • Output & visualization: textual reports, tables or graphs (bar/histogram/line/scatter) to communicate results.

Key Python constructs to use:

  • Loops and conditionals (for, while, if)
  • Comprehensions (list/dict/set) for concise transformations
  • Functions to modularize tasks
  • File handling (open/read/write) and the csv module for structured data
  • Dictionaries to implement frequency counts and grouping

Small example workflow (student marks analysis): read marks from a CSV, convert to numbers, compute mean/median/mode, find top scorers, and plot distribution.

# Example: read marks, compute mean
import csv
marks = []
with open('marks.csv') as f:
    reader = csv.reader(f)
    next(reader)  # skip header
    for row in reader:
        marks.append(int(row[1]))

mean = sum(marks)/len(marks)

Problem solving tips:

  • Start with small test data and print intermediate results.
  • Break the problem into functions (read_data, clean_data, analyze, visualize).
  • Use dictionaries for counting (e.g., frequency of grades) and sorting with key functions.
  • Handle edge cases (empty files, non-numeric entries) with try/except or validation checks.
📌 Examples
  • 1) Counting frequency of words in a text file: read file line by line, split into words, normalize to lowercase, use a dictionary to count and then sort by count to get most frequent words. Python sketch: from collections import Counter with open('essay.txt') as f: words = [w.strip('.,!?:;"').lower() for line in f for w in line.split()] counts = Counter(words) most_common = counts.most_common(5)
  • 2) Student marks analysis (CSV): read student name and marks, compute total, mean, median, mode, grade distribution and list top 3 students. Sketch: import csv students = [] with open('students.csv') as f: for name, mark in csv.reader(f): students.append((name, int(mark))) # compute mean, sort by marks for top 3
  • 3) Inventory management (dictionary): maintain product:quantity mapping, support add/remove/update, and display low-stock items (quantity < threshold). Sketch: inventory = {'pens': 50, 'books': 12} # update: inventory['pens'] -= 10 low_stock = [p for p,q in inventory.items() if q < 20]
  • 4) Temperature analysis (list): given daily temps, compute average, min, max, count days above average, and plot a line chart of temperature trend. Sketch: temps = [30.5, 32.0, 29.8, ...] avg = sum(temps)/len(temps) days_above = sum(1 for t in temps if t > avg)
  • 5) CSV data aggregation: group sales by region using a dictionary: for each row (region, amount) do totals[region] = totals.get(region, 0) + float(amount); then create a bar chart of totals per region.
🧮 Formulas
  1. \[Mean (average): mean = sum(x_i) / n Python: mean = sum(values)/len(values)\]
  2. \[Median: sort the list\]
    \[if n odd -> middle element\]
    \[if n even -> average of two middle elements Python sketch: sorted_vals = sorted(values)\]
    \[median = (sorted_vals[n//2] if n%2 else (sorted_vals[n//2 -1] + sorted_vals[n//2])/2)\]
  3. \[Mode: the value(s) with highest frequency Python: from collections import Counter\]
    \[mode = Counter(values).most_common(1)[0][0]\]
  4. \[Variance (population): var = (1/n) * sum((x_i - mean)^2) Standard deviation: sd = sqrt(var) Python sketch: import math\]
    \[var = sum((x-mean)**2 for x in values)/len(values)\]
    \[sd = math.sqrt(var)\]
  5. \[Percentage / proportion: percent = (part / whole) * 100 Useful for grade distribution and category shares.\]
  6. \[Sorting key for top-N: use sorted(items\]
    \[key=lambda x: x[1]\]
    \[reverse=True) to get items sorted by value (e.g.\]
    \[marks or totals).\]

Key Concepts

Data
Raw facts or values (numbers, text, etc.) that can be processed by a program.
Data Type
A classification that specifies the kind of data (e.g., int, float, str, list).
Mutable
Objects whose state or contents can be changed after creation (e.g., lists, dicts, sets).
Immutable
Objects that cannot be altered after creation (e.g., int, float, tuple, str).
List
An ordered, mutable collection of items, written with square brackets [].
Tuple
An ordered, immutable collection of items, written with parentheses ().
Dictionary
An unordered collection of key-value pairs, written with braces {}.
Set
An unordered collection of unique items, written with braces {}, useful for membership tests.
String
A sequence of characters used to store text, enclosed in quotes.
Indexing
Accessing an individual element of a sequence (list, tuple, string) using its position (index).
Slicing
Extracting a subsequence from a sequence using start:stop[:step] notation.
File Handling
Opening, reading, writing and closing files using built-in functions like open(), read(), write(), close().
File Modes
Mode strings used with open(), such as 'r' (read), 'w' (write, overwrite), 'a' (append), 'rb'/'wb' (binary).
CSV (Comma-Separated Values)
A common plain-text format for tabular data; Python's csv module helps read/write CSV files.
JSON
JavaScript Object Notation, a text format for structured data; use Python's json module to parse and serialize.
Exception
An error event that occurs during program execution; handled using try-except blocks.
Iterator
An object representing a stream of data; supports next() to fetch successive items and is obtained via iter().
Generator
A special iterator defined with yield or generator expressions that produces items lazily.
Comprehension
A concise way to create lists, sets or dicts from iterables using a compact syntax (e.g., [expr for var in iter]).
Type Conversion (Casting)
Explicitly converting one data type to another using functions like int(), float(), str(), list(), dict().

Practice Questions

  1. Differentiate between mutable and immutable data types in Python with examples. / पायथन में म्यूटेबल और इम्यूटेबल डेटा प्रकारों में उदाहरण सहित अंतर कीजिए।
    Show answer

    Mutable types can be changed in place (list, dict, set), while immutable types cannot be altered after creation (int, float, str, tuple); modifying an immutable value creates a new object. / म्यूटेबल प्रकार स्थान पर ही बदले जा सकते हैं (list, dict, set), जबकि इम्यूटेबल प्रकार बनने के बाद नहीं बदले जा सकते (int, float, str, tuple); इम्यूटेबल मान बदलने पर एक नई वस्तु बनती है।

  2. Given s = 'python', what is the output of s[1:4] and s[::-1]? / दिया गया है s = 'python', s[1:4] और s[::-1] का आउटपुट क्या है?
    Show answer

    s[1:4] gives 'yth' (indices 1,2,3 with stop exclusive); s[::-1] gives 'nohtyp' (the string reversed). / s[1:4] से 'yth' मिलता है (सूचकांक 1,2,3 जहाँ स्टॉप अपवर्जित है); s[::-1] से 'nohtyp' मिलता है (स्ट्रिंग उल्टी हुई)।

  3. Explain the difference between d['key'] and d.get('key') for dictionary access. / डिक्शनरी एक्सेस के लिए d['key'] और d.get('key') में अंतर समझाइए।
    Show answer

    d['key'] raises a KeyError if the key is missing, whereas d.get('key') returns None (or a given default) safely without raising an error. / यदि कुंजी अनुपस्थित हो तो d['key'] KeyError उठाता है, जबकि d.get('key') बिना त्रुटि उठाए सुरक्षित रूप से None (या दिया गया डिफ़ॉल्ट) लौटाता है।

  4. Why must dictionary keys be immutable while values can be of any type? / डिक्शनरी की कुंजियाँ इम्यूटेबल क्यों होनी चाहिए जबकि मान किसी भी प्रकार के हो सकते हैं?
    Show answer

    Dictionaries use a hash table where keys are hashed for O(1) lookup, so keys must be hashable/immutable to keep a stable hash, but values are not hashed and can be any object. / डिक्शनरी एक हैश टेबल का उपयोग करती है जहाँ कुंजियाँ O(1) लुकअप के लिए हैश की जाती हैं, इसलिए स्थिर हैश बनाए रखने हेतु कुंजियाँ हैशेबल/इम्यूटेबल होनी चाहिए, परंतु मान हैश नहीं होते और कोई भी वस्तु हो सकते हैं।

  5. Write a list comprehension to create a list of squares of numbers from 1 to 5. / 1 से 5 तक की संख्याओं के वर्गों की सूची बनाने के लिए एक लिस्ट कॉम्प्रिहेंशन लिखिए।
    Show answer

    squares = [x*x for x in range(1, 6)] produces [1, 4, 9, 16, 25]. / squares = [x*x for x in range(1, 6)] से [1, 4, 9, 16, 25] बनता है।

  6. Given A = {1,2,3} and B = {3,4,5}, find A | B, A & B and A - B. / दिया गया है A = {1,2,3} और B = {3,4,5}, A | B, A & B और A - B ज्ञात कीजिए।
    Show answer

    A | B (union) = {1,2,3,4,5}; A & B (intersection) = {3}; A - B (difference) = {1,2}. / A | B (संघ) = {1,2,3,4,5}; A & B (प्रतिच्छेदन) = {3}; A - B (अंतर) = {1,2}।

  7. What happens when int('12.3') is executed and how should the conversion be done correctly? / int('12.3') निष्पादित करने पर क्या होता है और रूपांतरण सही तरीके से कैसे किया जाना चाहिए?
    Show answer

    int('12.3') raises a ValueError because the string is not integer-format; convert with float('12.3') first, then int(float('12.3')) to get 12 (truncated). / int('12.3') ValueError उठाता है क्योंकि स्ट्रिंग पूर्णांक-प्रारूप में नहीं है; पहले float('12.3') से बदलें, फिर int(float('12.3')) से 12 (काट-छाँट कर) प्राप्त करें।

  8. Give two reasons to use a tuple instead of a list to store data. / डेटा संग्रहीत करने के लिए लिस्ट के बजाय ट्यूपल का उपयोग करने के दो कारण दीजिए।
    Show answer

    Tuples are used when data should not change (immutability protects fixed records like coordinates) and they can serve as dictionary keys; they are also slightly faster and use less memory than lists. / ट्यूपल का उपयोग तब होता है जब डेटा बदलना नहीं चाहिए (इम्यूटेबिलिटी निर्देशांक जैसे स्थिर रिकॉर्ड की रक्षा करती है) और वे डिक्शनरी की कुंजी बन सकते हैं; ये लिस्ट की तुलना में थोड़े तेज़ भी होते हैं और कम मेमोरी लेते हैं।

Related Laws & Principles

Explore all

Foundational laws & principles connected to this chapter — tap to open in the Laws Explorer.

Loading related laws…
Sourced from 261 content files · LLOS Learn · browse all chapters