> ## Documentation Index
> Fetch the complete documentation index at: https://genai.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 02-Data Structures & Comprehensions

> Master lists, tuples, dictionaries, sets, queues with deque, and learn Pythonic comprehensions.

# Python Data Structures & Comprehensions

This module covers Python's core data structures (Lists, Tuples, Dictionaries, Sets), queue operations using `deque`, and the powerful comprehension syntax used to create and transform them.

## Topics Covered

In this module, you'll learn:

1. [**Lists**: CRUD Operations and Sorting](#1-lists-crud-operations-and-sorting)
2. [**Tuples**: Operations, Indexing, and Slicing](#2-tuples-operations-indexing-and-slicing)
3. [**Dictionaries**: CRUD Operations and Sorting](#3-dictionaries-crud-operations-and-sorting)
4. [**Sets**: CRUD Operations and Sorting](#4-sets-crud-operations-and-sorting)
5. [**Queues**: Using `collections.deque`](#5-queues-using-collectionsdeque)
6. [**Why Comprehensions?**](#6-why-comprehensions)
7. [**List Comprehensions**](#7-list-comprehensions)
8. [**Dictionary Comprehensions**](#8-dictionary-comprehensions)
9. [**Set Comprehensions**](#9-set-comprehensions)
10. [**Generator Expressions**](#10-generator-expressions)
11. [**Comprehensions vs Loops & Best Practices**](#11-comprehensions-vs-loops--best-practices)

> **Try Yourself:** [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/DSA%20With%20Python/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/main/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises-colab.ipynb) | <a href="/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises.ipynb" download>📥 Download</a><br />
> **Verify Solutions:** [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/DSA%20With%20Python/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/main/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-colab.ipynb) | <a href="/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions.ipynb" download>📥 Download</a>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 1. Lists: CRUD Operations and Sorting

A **List** in Python is an ordered, mutable sequence of elements. It is one of the most widely used data structures.

### Create (C)

You can create a list by enclosing comma-separated values in square brackets `[]` or by using the `list()` constructor.

```python theme={null}
# Creating lists
languages = ["Python", "JavaScript"]
empty_list = []
numbers = list(range(1, 4))

print(languages)
print(numbers)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  ['Python', 'JavaScript']
  [1, 2, 3]
  ```
</Accordion>

### Read (R) - Indexing & Slicing

Elements in a list are accessed using zero-based indexing, negative indexing (from the end), or slicing (`list[start:stop:step]`).

```python theme={null}
fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]

# Accessing single elements (indexing)
print(fruits[0])    # First element: "Apple"
print(fruits[-1])   # Last element: "Elderberry"

# Extracting a sub-list (slicing)
print(fruits[1:4])  # Indices 1 to 3: ["Banana", "Cherry", "Date"]
print(fruits[:3])   # First 3 elements: ["Apple", "Banana", "Cherry"]
print(fruits[2:])   # Elements from index 2 to end: ["Cherry", "Date", "Elderberry"]
print(fruits[::2])  # Alternate elements: ["Apple", "Cherry", "Elderberry"]
print(fruits[::-1]) # Reversed list: ["Elderberry", "Date", "Cherry", "Banana", "Apple"]
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Apple
  Elderberry
  ['Banana', 'Cherry', 'Date']
  ['Apple', 'Banana', 'Cherry']
  ['Cherry', 'Date', 'Elderberry']
  ['Apple', 'Cherry', 'Elderberry']
  ['Elderberry', 'Date', 'Cherry', 'Banana', 'Apple']
  ```
</Accordion>

### Update (U)

Since lists are mutable, you can modify elements in-place, append new elements, insert at specific positions, or extend with another list.

```python theme={null}
colors = ["red", "green"]

# Modify in-place
colors[1] = "blue"

# Append (add to end)
colors.append("yellow")

# Insert at index 1
colors.insert(1, "orange")

# Extend (add multiple items)
colors.extend(["purple", "pink"])

print(colors)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  ['red', 'orange', 'blue', 'yellow', 'purple', 'pink']
  ```
</Accordion>

### Delete (D)

You can remove elements from a list using `.remove()`, `.pop()`, `.clear()`, or the `del` statement.

```python theme={null}
tasks = ["code", "test", "deploy", "debug"]

# Remove by value
tasks.remove("test")

# Remove by index (returns the removed value)
removed = tasks.pop(1)
print(f"Removed item: {removed}")

# Delete via index
del tasks[0]

print(tasks)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Removed item: deploy
  ['debug']
  ```
</Accordion>

### Sorting

Python lists can be sorted in-place using `.sort()` or out-of-place using the global `sorted()` function.

```python theme={null}
nums = [42, 7, 19, 88, 3]

# Out-of-place (returns a new sorted list)
new_nums = sorted(nums)
print("Original:", nums)
print("Sorted copy:", new_nums)

# In-place sorting
nums.sort()
print("Sorted in-place:", nums)

# Reverse sorting
nums.sort(reverse=True)
print("Reverse sorted in-place:", nums)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Original: [42, 7, 19, 88, 3]
  Sorted copy: [3, 7, 19, 42, 88]
  Sorted in-place: [3, 7, 19, 42, 88]
  Reverse sorted in-place: [88, 42, 19, 7, 3]
  ```
</Accordion>

### Exercise 1

Write a program to create a list of numbers, append `10`, insert `5` at index `0`, and then sort it in-place in descending order.

<Accordion title="Solution">
  ```python theme={null}
  nums = [12, 3, 45]
  nums.append(10)
  nums.insert(0, 5)
  nums.sort(reverse=True)
  print(nums)
  ```
</Accordion>

### Exercise 2

Given a list `arr = ["apple", "cherry", "banana"]`, remove the element `"cherry"` and print the sorted list.

<Accordion title="Solution">
  ```python theme={null}
  arr = ["apple", "cherry", "banana"]
  arr.remove("cherry")
  print(sorted(arr))
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 2. Tuples: Operations, Indexing, and Slicing

A **Tuple** is an ordered, **immutable** sequence of elements. Once created, a tuple's elements cannot be modified, added, or removed.

### Create (C)

Tuples are defined using parentheses `()` or the `tuple()` constructor. To define a tuple with a single element, you must include a trailing comma.

```python theme={null}
# Creating tuples
tup1 = (10, 20, 30)
empty_tup = ()
single_tup = (5,)  # Note the trailing comma
tup_from_list = tuple([1, 2, 3])

print(tup1)
print(single_tup)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  (10, 20, 30)
  (5,)
  ```
</Accordion>

### Read (R) - Indexing & Slicing

Tuples support the exact same indexing and slicing syntax as lists (zero-based indexing, negative indexing, and slicing with `[start:stop:step]`).

```python theme={null}
values = ("A", "B", "C", "D", "E")

# Indexing & Slicing
print(values[0])     # First element: "A"
print(values[-1])    # Last element: "E"
print(values[1:4])   # Slice: ("B", "C", "D")
print(values[::-1])  # Reversed tuple: ("E", "D", "C", "B", "A")
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  A
  E
  ('B', 'C', 'D')
  ('E', 'D', 'C', 'B', 'A')
  ```
</Accordion>

### Operations

Although immutable, tuples support common operations such as concatenation, repetition, membership testing, and element counting.

```python theme={null}
t1 = (1, 2)
t2 = (3, 4)

# Concatenation
t3 = t1 + t2
print("Concatenation:", t3)

# Repetition
t4 = t1 * 3
print("Repetition:", t4)

# Index and Count
chars = ("a", "b", "a", "c")
print("Count of 'a':", chars.count("a"))
print("First index of 'b':", chars.index("b"))

# Membership
print("a" in chars)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Concatenation: (1, 2, 3, 4)
  Repetition: (1, 2, 1, 2, 1, 2)
  Count of 'a': 2
  First index of 'b': 1
  True
  ```
</Accordion>

### Sorting

Because tuples are immutable, you cannot sort them in-place. You must use the `sorted()` function, which returns a new sorted **list**. You can convert this list back to a tuple if needed.

```python theme={null}
tup = (42, 7, 19, 3)
sorted_list = sorted(tup)
sorted_tup = tuple(sorted_list)

print("Original Tuple:", tup)
print("Sorted Tuple:", sorted_tup)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Original Tuple: (42, 7, 19, 3)
  Sorted Tuple: (3, 7, 19, 42)
  ```
</Accordion>

### Exercise 1

Create a tuple containing elements `10`, `20`, `30`, `40`, `50`. Extract the middle three elements using slicing.

<Accordion title="Solution">
  ```python theme={null}
  tup = (10, 20, 30, 40, 50)
  print(tup[1:4])
  ```
</Accordion>

### Exercise 2

Given the tuple `data = (5, 2, 9, 1)`, write a program to sort it in ascending order and print the result as a tuple.

<Accordion title="Solution">
  ```python theme={null}
  data = (5, 2, 9, 1)
  sorted_data = tuple(sorted(data))
  print(sorted_data)
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 3. Dictionaries: CRUD Operations and Sorting

A **Dictionary** in Python is a mutable, key-value collection. Keys must be unique and immutable.

### Create (C)

Create dictionaries using curly braces `{}` containing key-value pairs or the `dict()` constructor.

```python theme={null}
# Creating dictionaries
student = {"name": "Alice", "age": 25}
empty_dict = {}
colors = dict(red="#FF0000", green="#00FF00")

print(student)
print(colors)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {'name': 'Alice', 'age': 25}
  {'red': '#FF0000', 'green': '#00FF00'}
  ```
</Accordion>

### Read (R)

Values are retrieved using key indexing or the safer `.get()` method.

```python theme={null}
profile = {"username": "coder1", "email": "coder1@test.com"}

# Key lookup
print(profile["username"])

# Safe lookup using get() (returns None or default value if missing)
print(profile.get("age"))
print(profile.get("age", 18))

# Accessing keys, values, and items
print(list(profile.keys()))
print(list(profile.values()))
print(list(profile.items()))
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  coder1
  None
  18
  ['username', 'email']
  ['coder1', 'coder1@test.com']
  [('username', 'coder1'), ('email', 'coder1@test.com')]
  ```
</Accordion>

### Update (U)

You can add new key-value pairs or modify existing ones simply by assigning to a key, or by using `.update()`.

```python theme={null}
car = {"brand": "Tesla", "model": "Model 3"}

# Add/Modify key-value pairs
car["year"] = 2021
car["model"] = "Model Y"

# Batch update
car.update({"color": "red", "battery": "Long Range"})

print(car)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {'brand': 'Tesla', 'model': 'Model Y', 'year': 2021, 'color': 'red', 'battery': 'Long Range'}
  ```
</Accordion>

### Delete (D)

Items can be removed using `del`, `.pop()` (returns value), `.popitem()` (removes last inserted pair), or `.clear()`.

```python theme={null}
inventory = {"apples": 10, "bananas": 5, "peaches": 2}

# Remove by key using pop
popped_val = inventory.pop("bananas")
print(f"Removed bananas value: {popped_val}")

# Remove last inserted item
last_item = inventory.popitem()
print(f"Removed last item: {last_item}")

# Delete keyword
del inventory["apples"]

print(inventory)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Removed bananas value: 5
  Removed last item: ('peaches', 2)
  {}
  ```
</Accordion>

### Sorting

Dictionaries can be sorted by keys or values using the `sorted()` function on their items.

```python theme={null}
scores = {"Charlie": 90, "Alice": 95, "Bob": 85}

# Sort by Keys (alphabetical)
sorted_by_keys = dict(sorted(scores.items()))
print("Sorted by keys:", sorted_by_keys)

# Sort by Values (ascending scores)
sorted_by_values = dict(sorted(scores.items(), key=lambda item: item[1]))
print("Sorted by values:", sorted_by_values)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Sorted by keys: {'Alice': 95, 'Bob': 85, 'Charlie': 90}
  Sorted by values: {'Bob': 85, 'Charlie': 90, 'Alice': 95}
  ```
</Accordion>

### Exercise 1

Create a dictionary representing a book with key-value pairs for `title`, `author`, and `price`. Update the price to `499`, add a new key `year` as `2024`, and print all keys in the dictionary.

<Accordion title="Solution">
  ```python theme={null}
  book = {"title": "Python Basics", "author": "John Doe", "price": 399}
  book["price"] = 499
  book["year"] = 2024
  print(list(book.keys()))
  ```
</Accordion>

### Exercise 2

Given `d = {"z": 1, "y": 2, "x": 3}`, sort the dictionary by keys in ascending order and print the resulting dictionary.

<Accordion title="Solution">
  ```python theme={null}
  d = {"z": 1, "y": 2, "x": 3}
  sorted_d = dict(sorted(d.items()))
  print(sorted_d)
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 4. Sets: CRUD Operations and Sorting

A **Set** in Python is an unordered collection of unique, immutable elements. Sets do not allow duplicate values.

### Create (C)

Sets are created using curly braces `{}` containing elements or the `set()` constructor. Note that an empty set must be created using `set()`, as `{}` creates an empty dictionary.

```python theme={null}
# Creating sets
numbers = {1, 2, 3, 3}  # Duplicates are automatically removed
print(numbers)

empty_set = set()
names = set(["Alice", "Bob"])
print(names)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {1, 2, 3}
  {'Alice', 'Bob'}
  ```
</Accordion>

### Read (R)

Since sets are unordered, they do not support indexing or slicing. You read elements by checking membership (`in`) or by iterating over the set.

```python theme={null}
chars = {"a", "b", "c"}

# Membership test
print("a" in chars)
print("z" in chars)

# Iteration
for char in chars:
    print(char)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  True
  False
  b
  c
  a
  ```
</Accordion>

### Update (U)

You can add elements using `.add()` (for a single element) or `.update()` (for multiple elements).

```python theme={null}
countries = {"India", "USA"}

# Add single item
countries.add("UK")

# Add multiple items (can pass list, tuple, set, etc.)
countries.update(["Canada", "Germany"])

print(countries)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {'Germany', 'India', 'UK', 'Canada', 'USA'}
  ```
</Accordion>

### Delete (D)

Remove elements using `.remove()` (raises KeyError if not found), `.discard()` (safe, does not raise error), `.pop()` (removes and returns an arbitrary element), or `.clear()`.

```python theme={null}
brands = {"Nike", "Adidas", "Puma"}

# Remove element (raises error if missing)
brands.remove("Adidas")

# Discard element safely (no error if missing)
brands.discard("Reebok")

# Pop arbitrary element
popped = brands.pop()
print(f"Popped brand: {popped}")

print(brands)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Popped brand: Nike
  {'Puma'}
  ```
</Accordion>

### Sorting

Since sets are inherently unordered, they cannot be sorted in-place. However, you can use the `sorted()` function, which returns a sorted list of the set's elements.

```python theme={null}
values = {42, 3, 17, 8}

# Sorting a set returns a list
sorted_values = sorted(values)
print("Sorted values list:", sorted_values)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Sorted values list: [3, 8, 17, 42]
  ```
</Accordion>

### Exercise 1

Create an empty set, add elements `10`, `20`, and `30` to it, remove `20`, and verify if `20` is still in the set.

<Accordion title="Solution">
  ```python theme={null}
  s = set()
  s.add(10)
  s.add(20)
  s.add(30)
  s.remove(20)
  print(20 in s)
  ```
</Accordion>

### Exercise 2

Given a set `my_set = {15, 5, 25, 10}`, sort the elements of the set and print the result.

<Accordion title="Solution">
  ```python theme={null}
  my_set = {15, 5, 25, 10}
  print(sorted(my_set))
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 5. Queues: Using `collections.deque`

A queue is a linear data structure that follows the **FIFO (First-In, First-Out)** principle.

Although you can use a Python list as a queue by calling `list.pop(0)`, this operation is inefficient. Shifting elements at index 0 requires **$O(n)$ time complexity**.

Python's **`collections.deque`** (double-ended queue) is specifically designed to allow fast appends and pops from both ends in **$O(1)$ time complexity**.

### Creating and Enqueuing Elements

Import `deque` from `collections`, and use `.append()` to enqueue items to the right side of the queue.

```python theme={null}
from collections import deque

# Create a queue
queue = deque()

# Enqueue (adding elements)
queue.append("Alice")
queue.append("Bob")
queue.append("Charlie")

print("Queue status:", queue)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Queue status: deque(['Alice', 'Bob', 'Charlie'])
  ```
</Accordion>

### Dequeuing Elements

Use `.popleft()` to remove and return elements from the left side (front of the queue), preserving the FIFO order.

```python theme={null}
# Dequeue (removing elements)
first = queue.popleft()
print(f"Served: {first}")

second = queue.popleft()
print(f"Served: {second}")

print("Remaining Queue:", queue)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Served: Alice
  Served: Bob
  Remaining Queue: deque(['Charlie'])
  ```
</Accordion>

### Add to Front / Remove from Back

Because `deque` is double-ended, you can also perform LIFO operations or add to the front:

* `appendleft(item)`: Add an element to the front.
* `pop()`: Remove and return an element from the back.

```python theme={null}
q = deque(["Job1", "Job2"])
q.appendleft("UrgentJob")  # Added to front
print(q)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  deque(['UrgentJob', 'Job1', 'Job2'])
  ```
</Accordion>

### Exercise 1

Create a queue using `deque` containing `["user1", "user2"]`. Enqueue `"user3"`, dequeue the first user in line, and print the remaining queue.

<Accordion title="Solution">
  ```python theme={null}
  from collections import deque

  q = deque(["user1", "user2"])
  q.append("user3")
  served = q.popleft()
  print("Served:", served)
  print("Queue:", q)
  ```
</Accordion>

### Exercise 2

Write a program to demonstrate how to use `deque` as a stack (Last-In, First-Out) using `.append()` and `.pop()`.

<Accordion title="Solution">
  ```python theme={null}
  from collections import deque

  stack = deque()
  stack.append("plate1")
  stack.append("plate2")
  print(stack.pop())  # returns "plate2"
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 6. Why Comprehensions?

Suppose we want to create a list containing the squares of numbers from `1` to `5`. A common approach is to use a `for` loop.

```python theme={null}
squares = []
for number in range(1, 6):
    squares.append(number ** 2)
print(squares)
```

<Accordion title="Show Output">
  ```text theme={null}
  [1, 4, 9, 16, 25]
  ```
</Accordion>

Python provides **comprehensions** to perform the same task in a cleaner, single-line expression:

```python theme={null}
squares = [number ** 2 for number in range(1, 6)]
print(squares)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  [1, 4, 9, 16, 25]
  ```
</Accordion>

### General Syntax

```python theme={null}
[expression for item in iterable]
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  Error executing code: name 'iterable' is not defined
  ```
</Accordion>

* **expression** → Value to be added to the collection.
* **item** → Current element from the iterable.
* **iterable** → Any iterable object such as a string, list, tuple, range, or set.

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 7. List Comprehensions

A **list comprehension** creates a new list by applying an expression to each element of an iterable.

### Basic List Comprehension

```python theme={null}
numbers = [1, 2, 3, 4, 5]
squares = [num ** 2 for num in numbers]
print(squares)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  [1, 4, 9, 16, 25]
  ```
</Accordion>

### Filtering with `if`

You can filter elements by adding an `if` clause at the end.

```python theme={null}
numbers = range(1, 11)
evens = [num for num in numbers if num % 2 == 0]
print(evens)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  [2, 4, 6, 8, 10]
  ```
</Accordion>

### Using `if-else` (Transformation)

To transform values differently based on a condition, place the `if-else` clause **before** the `for` loop.

```python theme={null}
numbers = range(1, 6)
labels = ["Even" if num % 2 == 0 else "Odd" for num in numbers]
print(labels)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  ['Odd', 'Even', 'Odd', 'Even', 'Odd']
  ```
</Accordion>

### Nested List Comprehensions (Flattening)

You can nest comprehensions to work with multi-dimensional lists (e.g., flattening a matrix).

```python theme={null}
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [num for row in matrix for num in row]
print(flat)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  [1, 2, 3, 4, 5, 6]
  ```
</Accordion>

### Exercise 1

Create a list containing the lengths of each word in the list `["Python", "FastAPI", "API"]` using a list comprehension.

<Accordion title="Solution">
  ```python theme={null}
  words = ["Python", "FastAPI", "API"]
  lengths = [len(word) for word in words]
  print(lengths)
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 8. Dictionary Comprehensions

A **dictionary comprehension** provides a concise way to create dictionaries from iterables.

### Basic Dictionary Comprehension

```python theme={null}
numbers = [1, 2, 3, 4, 5]
squares = {num: num ** 2 for num in numbers}
print(squares)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
  ```
</Accordion>

### Filtering in Dictionary Comprehensions

```python theme={null}
scores = {"Alice": 85, "Bob": 72, "Charlie": 90}
passed = {name: score for name, score in scores.items() if score >= 80}
print(passed)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {'Alice': 85, 'Charlie': 90}
  ```
</Accordion>

### Exercise 1

Given the list `["a", "b", "c"]`, create a dictionary where each character is a key, and its ASCII code (`ord(char)`) is the value.

<Accordion title="Solution">
  ```python theme={null}
  chars = ["a", "b", "c"]
  ascii_dict = {char: ord(char) for char in chars}
  print(ascii_dict)
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 9. Set Comprehensions

A **set comprehension** creates a set. Since sets store unique values, duplicates are automatically removed.

### Basic Set Comprehension

```python theme={null}
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_squares = {num ** 2 for num in numbers}
print(unique_squares)
```

Output ?

<Accordion title="Show Output">
  ```text theme={null}
  {1, 4, 9, 16, 25}
  ```
</Accordion>

### Exercise 1

Extract all unique vowels from the string `"Artificial Intelligence"` in lowercase using a set comprehension.

<Accordion title="Solution">
  ```python theme={null}
  text = "Artificial Intelligence"
  vowels = {char.lower() for char in text if char.lower() in "aeiou"}
  print(vowels)
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 10. Generator Expressions

A **generator expression** is similar to a list comprehension, but instead of creating the entire list in memory, it produces values **one at a time (lazy evaluation)** using iterators.

### Syntax

Replace square brackets `[]` with parentheses `()`.

```python theme={null}
# This is a generator expression
squares_gen = (num ** 2 for num in range(1, 6))

print(squares_gen)
# Retrieve values using next() or a loop
print(next(squares_gen))
print(next(squares_gen))
```

Output

<Accordion title="Show Output">
  ```text theme={null}
  <generator object <genexpr> at ...>
  1
  4
  ```
</Accordion>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

# 11. Comprehensions vs Loops & Best Practices

| Feature      | Traditional Loop         | Comprehension                     | Generator Expression     |
| ------------ | ------------------------ | --------------------------------- | ------------------------ |
| Readability  | Better for complex logic | Better for simple transformations | Ideal for streaming data |
| Memory Usage | Moderate                 | Higher (stores entire collection) | Minimal ($O(1)$ memory)  |
| Performance  | Good                     | Fast                              | Fast (lazy computation)  |

### Best Practices

* Use comprehensions for **simple, readable** mappings or filter operations.
* Avoid nesting comprehensions more than 2 levels deep to keep code readable.
* Use **generator expressions** when working with large or infinite datasets.
* If the loop body contains complex conditional logic, prefer a standard `for` loop.

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

## Practice

To reinforce what you've learned in this section, practice with the interactive follow-along notebook:

<CardGroup cols={1}>
  <Card title="Follow-Along Practice" icon="laptop-code">
    Practice lists, tuples, dictionaries, sets operations, deque queues, list/dict/set comprehensions, and generator expressions.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/DSA%20With%20Python/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/genai-course/blob/main/public/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises-colab.ipynb) | <a href="/notebooks/workshop-notebooks/02-ds-comprehensions/02-ds-comprehensions-exercises.ipynb" download>📥 Download</a>
  </Card>
</CardGroup>

***

<div align="right">[Back to Top ↑](#topics-covered)</div>

## Summary

In this module, you learned how to manipulate Python's core data structures (Lists, Tuples, Dictionaries, Sets), use double-ended queues, and write clean, memory-efficient comprehensions.
