Python Programming for Business Analytics

Chapter 3
Data Structures and Control Flow

Diploma in Business Analytics
Python Programming for Business Analytics   •   Diploma

Data Structures and Control Flow

Introduction

Business analytics depends on more than calculating averages or producing charts. Analysts must collect, organize, filter, transform and evaluate information before meaningful conclusions can be drawn. Python provides two closely related foundations for these tasks: data structures, which store and organize values, and control-flow statements, which determine how a program processes those values.

A sales transaction, for example, may contain a product code, customer segment, quantity, price and transaction date. A Python program can store these attributes in a dictionary, store many transactions in a list, remove duplicate regions with a set, and apply business rules with conditions and loops. Together, these features allow analysts to construct repeatable and auditable solutions.

This chapter focuses on lists, tuples, sets, dictionaries, conditions, loops and comprehensions. Examples use ordinary Python and are designed for diploma-level business analytics applications.

Learning Objectives

By the end of this chapter, you should be able to:

  1. Explain the purpose and characteristics of common Python data structures.
  2. Select an appropriate structure for a business analytics problem.
  3. Access, modify and validate structured data.
  4. Implement business rules using conditional statements.
  5. Process collections using for and while loops.
  6. Use comprehensions to create concise, readable transformations.
  7. Combine data structures and control flow in practical applications.
  8. Identify risks involving missing data, duplicate values, data types and governance.

1. Data Structures as Analytical Models

A data structure is a formal way of storing data so that it can be accessed and manipulated. The correct structure depends on the questions the program must answer.

StructureMain propertyTypical analytical use
ListOrdered and changeable collectionMonthly sales, customer records, product quantities
TupleOrdered and generally unchangeable collectionFixed coordinates, record-like values, function results
SetUnordered collection of unique valuesDistinct regions, duplicate removal, membership testing
DictionaryKey–value mappingProduct-to-price lookup, customer attributes, configuration rules

Python collections can contain strings, numbers, Boolean values, other collections or mixtures of types. In professional work, however, consistent types are usually preferable because they make validation and later analysis safer.

1.1 Lists

A list preserves order and can be changed after creation.

monthly_sales = [12500, 14300, 13800, 15100]

Positions are indexed from zero:

first_month = monthly_sales[0]
last_month = monthly_sales[-1]
selected_months = monthly_sales[1:3]

The slice monthly_sales[1:3] includes positions 1 and 2 but excludes position 3. This half-open convention is important when selecting periods.

Lists can be modified with methods such as:

monthly_sales.append(16200)
monthly_sales.extend([15800, 17100])
monthly_sales.insert(0, 11900)
monthly_sales.remove(13800)
last_value = monthly_sales.pop()

remove() deletes the first matching value and raises an error if the value is absent. pop() removes and returns an item; without an index it removes the final item. For safer deletion, membership can be checked first.

if 13800 in monthly_sales:
    monthly_sales.remove(13800)

Useful list functions include len(), sum(), min(), max() and sorted(). These functions assume that the values are compatible—for example, sum() requires numeric values.

average_sales = sum(monthly_sales) / len(monthly_sales)

This calculation is valid only when the list is non-empty and contains numeric observations. In a real dataset, missing or invalid values should be handled explicitly rather than silently included.

1.2 Tuples

A tuple is ordered but normally cannot be changed after creation.

store_location = ("North", "Manchester")

Tuples are useful for fixed groups of values. They communicate that the structure represents one stable record or coordinate rather than a collection intended for frequent modification.

region, city = store_location

This is called unpacking. The number of variables must match the number of values unless extended unpacking is used.

Although a tuple itself is immutable, it may contain a mutable object such as a list. Therefore, “immutable” means that the tuple’s references cannot be reassigned, not that every nested object is permanently unchangeable.

1.3 Sets

A set stores unique values and does not provide a meaningful positional order.

regions = {"North", "South", "North", "West"}
print(regions)      # {'North', 'South', 'West'}

Sets are valuable for distinct-value analysis and fast membership testing.

registered_regions = {"North", "South", "East", "West"}
transaction_regions = {"North", "West"}
unknown_regions = transaction_regions - registered_regions

Important set operations include:

  • Union: A | B, values in either set.
  • Intersection: A & B, values in both sets.
  • Difference: A - B, values in the first set but not the second.
  • Symmetric difference: A ^ B, values in either set but not both.

Set elements must be hashable. Strings, numbers and tuples containing hashable values can be elements; lists and dictionaries cannot.

1.4 Dictionaries

A dictionary maps keys to values.

product = {
    "code": "P104",
    "category": "Stationery",
    "unit_price": 4.50,
    "stock": 120
}

Values are retrieved by key rather than position:

price = product["unit_price"]

Using a missing key with square brackets raises KeyError. The get() method allows a default value:

supplier = product.get("supplier", "Unknown")

Dictionaries can be updated:

product["stock"] = 115
product["reorder_level"] = 25

Useful views include keys(), values() and items():

for field, value in product.items():
    print(field, value)

Dictionary keys must be unique. Assigning a value to an existing key replaces the earlier value. This makes dictionaries suitable for lookups, but it also means that using a non-unique business identifier as a key can accidentally discard records.

2. Choosing the Appropriate Structure

Structure selection should follow the analytical operation, not personal preference.

  • Use a list when order matters or records will be added or removed.
  • Use a tuple for a fixed, record-like grouping.
  • Use a set when uniqueness and membership are central.
  • Use a dictionary when values must be retrieved using meaningful labels.

A list of dictionaries is a common representation of small tabular data:

orders = [
    {"order_id": "A101", "region": "North", "value": 850},
    {"order_id": "A102", "region": "South", "value": 420},
    {"order_id": "A103", "region": "North", "value": 1250}
]

This is readable and useful for introductory programs. Large-scale analytics normally uses specialized tabular tools, such as pandas, after the underlying Python concepts have been understood.

3. Conditions and Business Rules

Conditional statements allow a program to select actions based on data. The basic form is:

if condition:
    action_if_true
elif another_condition:
    alternative_action
else:
    default_action

Indentation defines the block belonging to each branch. Python conventionally uses four spaces.

3.1 Comparison and Logical Operators

Common comparison operators are ==, !=, <, >, <= and >=. Logical operators combine conditions:

  • and: every condition must be true.
  • or: at least one condition must be true.
  • not: reverses a Boolean result.
order_value = 850
customer_type = "business"

if order_value >= 1000 and customer_type == "business":
    discount_rate = 0.10
elif order_value >= 500:
    discount_rate = 0.05
else:
    discount_rate = 0.00

The conditions are evaluated from top to bottom. Once a true branch is found, later branches are skipped. Ordering therefore matters. A broad condition placed first may prevent a more specific condition from being evaluated.

3.2 Truthiness and Explicit Validation

Python treats some values as false in a Boolean context, including False, None, 0, empty strings and empty collections. Other values are treated as true.

customer_email = ""
if customer_email:
    status = "Email supplied"
else:
    status = "Email missing"

Truthiness is convenient, but it should not replace precise validation. For example, zero may be a valid quantity even though it is false in a Boolean context. A rule requiring a non-negative quantity should be stated explicitly:

if quantity is None:
    status = "Missing"
elif quantity < 0:
    status = "Invalid"
else:
    status = "Valid"

The identity operator is is generally used for singleton values such as None; equality == is used to compare values.

4. Loops for Repeated Processing

4.1 for Loops

A for loop processes each item in an iterable.

sales = [120, 85, 210]
total = 0

for amount in sales:
    total += amount

This loop is clearer and less error-prone than manually referring to each position. Dictionaries can be iterated through keys, values or key–value pairs.

region_totals = {"North": 1200, "South": 950, "West": 1430}
for region, total in region_totals.items():
    if total >= 1000:
        print(region)

enumerate() supplies both position and value:

for position, amount in enumerate(sales, start=1):
    print(position, amount)

zip() processes corresponding elements from multiple iterables. It stops when the shortest iterable is exhausted.

products = ["Pen", "Notebook", "Folder"]
quantities = [10, 6, 4]
for product_name, quantity in zip(products, quantities):
    print(product_name, quantity)

4.2 while Loops

A while loop continues while a condition remains true.

stock = 5
units_sold = 0

while stock > 0:
    stock -= 1
    units_sold += 1

A loop-control variable must eventually change, or the program may never terminate. In business applications, while loops are useful for repeated interaction, controlled simulation or processing until a condition is met. For straightforward collection processing, for loops are usually preferable.

4.3 break and continue

break exits a loop immediately. continue skips the remainder of the current iteration.

for order in orders:
    if order["value"] < 0:
        break
    if order["value"] == 0:
        continue
    print(order["order_id"])

These statements can be useful, but excessive use may make logic difficult to audit. Clear validation and well-named functions are often better than deeply nested control flow.

5. Comprehensions

A comprehension creates a collection from an iterable in a compact form.

sales = [120, 85, 210, 60]
high_sales = [amount for amount in sales if amount >= 100]

The general list-comprehension pattern is:

[result for item in collection if condition]

The condition is optional:

with_tax = [round(amount * 1.20, 2) for amount in sales]

A set comprehension creates unique results:

regions = {order["region"] for order in orders}

A dictionary comprehension creates key–value pairs:

order_values = {order["order_id"]: order["value"] for order in orders}

Nested comprehensions are possible, but readability should take priority over compactness. If a comprehension contains complex conditions or several transformations, a conventional loop may communicate the business rule more effectively.

6. Worked Application: Order Screening and Regional Reporting

Consider the following illustrative dataset:

orders = [
    {"id": "O100", "region": "North", "value": 1200, "status": "paid"},
    {"id": "O101", "region": "South", "value": 450, "status": "paid"},
    {"id": "O102", "region": "North", "value": 0, "status": "cancelled"},
    {"id": "O103", "region": "West", "value": 800, "status": "paid"}
]

The business requirements are:

  1. Consider only paid orders.
  2. Classify paid orders of at least 1,000 as “Priority”.
  3. Identify distinct active regions.
  4. Calculate regional paid-order totals.

First, filter the valid records:

paid_orders = [
    order for order in orders
    if order["status"] == "paid" and order["value"] > 0
]

The resulting records are O100, O101 and O103. A set identifies active regions:

active_regions = {order["region"] for order in paid_orders}

The result is {"North", "South", "West"}; set display order should not be relied upon.

Classification can be added with a loop:

for order in paid_orders:
    if order["value"] >= 1000:
        order["priority"] = "Priority"
    else:
        order["priority"] = "Standard"

Regional totals require accumulation. A dictionary is appropriate because each region maps to one total:

regional_totals = {}

for order in paid_orders:
    region = order["region"]
    regional_totals[region] = regional_totals.get(region, 0) + order["value"]

The result is:

RegionPaid-order total
North1,200
South450
West800

This example illustrates a general pattern: a list stores records, dictionaries represent record attributes and aggregations, a set identifies unique categories, conditions enforce business rules, and loops perform repeated processing.

7. Case Study: Inventory Reorder Screening

Background

The fictional company BrightOffice supplies stationery to small businesses. Its operations team wants a simple Python program to identify products requiring replenishment. The inventory data contains product code, stock level, reorder level and whether the product is currently active.

Problem

The company must exclude discontinued products, identify active products at or below their reorder level, and assign an urgency category. A poor solution could reorder discontinued products or overlook products with zero stock.

Analysis and Approach

A list of dictionaries represents the inventory:

inventory = [
    {"code": "P01", "stock": 12, "reorder_level": 20, "active": True},
    {"code": "P02", "stock": 45, "reorder_level": 15, "active": True},
    {"code": "P03", "stock": 0, "reorder_level": 10, "active": True},
    {"code": "P04", "stock": 5, "reorder_level": 10, "active": False}
]

reorder_list = []
for item in inventory:
    if not item["active"]:
        continue
    if item["stock"] <= item["reorder_level"]:
        if item["stock"] == 0:
            urgency = "Critical"
        else:
            urgency = "Review"
        reorder_list.append({"code": item["code"], "urgency": urgency})

Outcome

The reorder list contains P01 with “Review” urgency and P03 with “Critical” urgency. P02 is sufficiently stocked, while P04 is excluded because it is inactive.

Learning Points

The sequence of conditions reflects policy priorities. Activity is checked before stock because discontinued products should never be reordered. Zero stock receives a special classification because it is a more urgent case than merely being below the reorder level. In production, the rules should be documented, tested against boundary values, and approved by the inventory manager.

8. Data Quality, Efficiency and Governance

Missing and Invalid Data

Business records may contain missing keys, empty strings, unexpected categories or values stored as text. Programs should validate inputs before applying calculations.

raw_quantity = "12"
try:
    quantity = int(raw_quantity)
except ValueError:
    quantity = None

Validation should distinguish missing, invalid and valid values. Treating all three as zero can produce misleading stock, revenue or customer measures.

Aliasing and Copying

Two variables may refer to the same list:

original = [1, 2, 3]
backup = original
backup.append(4)

Both variables now refer to [1, 2, 3, 4]. To create a shallow copy, use original.copy() or original[:]. Nested structures may require deeper copying, and the implications should be understood before modifying data.

Efficiency

Membership testing in a set is generally more appropriate than repeatedly searching a long list when uniqueness is not required. Dictionaries are also suitable for direct lookups by key. Nevertheless, clarity and correctness should come before premature optimization. For large datasets, database queries or vectorized analytical libraries may be more suitable than manually iterating through every record in Python.

Governance and Ethics

Automated business rules can affect customers, suppliers and employees. Analysts should therefore:

  • document rule definitions and thresholds;
  • preserve source data and transformation steps;
  • avoid silently overwriting original records;
  • restrict access to personal or commercially sensitive data;
  • test rules for edge cases and unintended discrimination;
  • provide a review process for exceptions;
  • record assumptions, version changes and approval responsibility.

A program that is technically correct but based on an unjustified threshold can still produce poor managerial decisions. Reproducibility and accountability are essential parts of analytical programming.

Best Practices

  1. Choose structures according to required operations.
  2. Use meaningful variable and key names.
  3. Keep business rules explicit and readable.
  4. Validate missing, negative and unexpected values.
  5. Avoid relying on set order.
  6. Check that dictionary keys are unique identifiers.
  7. Prefer for loops for ordinary collection processing.
  8. Use comprehensions for simple transformations, not complicated logic.
  9. Test boundaries such as zero, empty collections and exact thresholds.
  10. Separate raw data from transformed data when auditability matters.

Chapter Summary

Python data structures provide practical models for business information. Lists store ordered, changeable collections; tuples represent fixed groups; sets manage unique values and membership; and dictionaries map meaningful keys to values. These structures can be combined to represent records and small tabular datasets.

Conditional statements implement business rules by selecting actions according to Boolean expressions. for loops process collections, while while loops repeat actions until a condition changes. break, continue, enumerate() and zip() support controlled iteration. Comprehensions provide concise transformations when the underlying logic remains clear.

Effective analytical programming also requires validation, careful handling of missing data, awareness of aliasing, appropriate structure selection and attention to governance. Business rules should be explicit, tested at boundary conditions and documented so that results are reproducible and accountable.

Key Terms

Data structure: A way of organizing data for access and manipulation.

List: An ordered, mutable Python collection.

Tuple: An ordered collection that cannot normally be modified after creation.

Set: An unordered collection of unique, hashable values.

Dictionary: A collection of key–value associations.

Key: A unique identifier used to retrieve a dictionary value.

Index: An integer position used to access an item in an ordered collection.

Slice: A range-based selection from an ordered collection.

Mutable: Capable of being changed after creation.

Immutable: Not normally changeable after creation.

Condition: An expression that evaluates to True or False.

Iteration: One repetition of a loop.

Iterable: An object whose values can be processed sequentially.

Comprehension: A compact expression for constructing a collection.

Truthiness: Python’s evaluation of a value as true or false in a Boolean context.

Validation: Checking whether data meets defined quality requirements.

Aliasing: The situation in which multiple variables refer to the same object.

Business rule: A defined condition or policy governing an organizational decision.

Aggregation: Combining multiple records into a summary value.

Review Questions

Short Answer Questions

  1. What is the principal difference between a list and a tuple?
  2. Why are sets useful when identifying distinct business categories?
  3. What happens when a dictionary key is assigned a new value?
  4. When is a while loop appropriate?
  5. What is the purpose of enumerate()?

Long Answer Questions

  1. Compare lists, tuples, sets and dictionaries, including one business analytics use for each.
  2. Explain how if, elif and else work, and why the order of conditions matters.
  3. Discuss the advantages and limitations of comprehensions compared with conventional loops.
  4. Explain how a list of dictionaries can represent a small table of business records.
  5. Describe the main data-quality and governance risks when implementing automated business rules.

Analytical / Application Questions

  1. Design a Python data structure for storing customer ID, segment, annual spend and account status for multiple customers. Justify your choice.
  2. Write a program that filters paid orders above a specified value and calculates totals by region. Identify at least two boundary cases that should be tested.
  3. A company’s reorder program includes inactive products and treats missing stock as zero. Explain the risks and propose improved validation and control-flow logic.

Multiple Choice Questions with Answers

Question 1

Which Python data structure is most appropriate for storing unique region names?

A. List

B. Tuple

C. Set

D. Dictionary

Correct Answer: C. Set

Question 2

What does orders[1:3] select from a list?

A. Items at positions 1 and 2

B. Items at positions 1, 2 and 3

C. Only the item at position 3

D. Items at positions 0 and 1

Correct Answer: A. Items at positions 1 and 2

Question 3

Which dictionary method returns a default value when a key is missing?

A. find()

B. get()

C. search()

D. default()

Correct Answer: B. get()

Question 4

What is the main purpose of a for loop in the examples?

A. To define a dictionary key

B. To process each item in an iterable

C. To remove all duplicate values

D. To prevent every condition from running

Correct Answer: B. To process each item in an iterable

Question 5

Which operator tests whether two values are equal?

A. =

B. !=

C. ==

D. =>

Correct Answer: C. ==

Question 6

What is the result of the set expression A & B?

A. Values in either set

B. Values in both sets

C. Values only in A

D. All duplicate values removed from A only

Correct Answer: B. Values in both sets

Question 7

Which statement about a list comprehension is correct?

A. It can create a new list from an iterable

B. It can only process dictionaries

C. It always modifies the original list

D. It cannot include a condition

Correct Answer: A. It can create a new list from an iterable

Question 8

Why should a missing dictionary key sometimes be handled with get() rather than square brackets?

A. get() sorts the dictionary

B. get() prevents all type errors

C. get() can return a default instead of raising KeyError

D. get() converts the key into a set

Correct Answer: C. get() can return a default instead of raising KeyError

Question 9

What is the likely result of assigning backup = original and then modifying backup?

A. Only backup changes because it is automatically copied

B. Both names refer to the changed object

C. The original becomes a tuple

D. Python raises a syntax error

Correct Answer: B. Both names refer to the changed object

Question 10

In the inventory case, why is the active-status condition checked before the reorder condition?

A. To ensure discontinued products are not reordered

B. To convert stock into a string

C. To guarantee that sets preserve order

D. To make every product critical

Correct Answer: A. To ensure discontinued products are not reordered

Python Programming for Business Analytics
Chapter 3 of 14