← Home

Ch 6 — Data Structures

Ch 6 — Data Structures

Tracking a single process’s RAM is trivial. Tracking all 300 processes, their PIDs, their snapshots over time, and the unique set of process names currently running — that requires real data structures. This chapter gives Aryan the containers that will hold the heart of the RAM manager.


range

A lazy sequence of integers. Produces values on demand rather than building a whole list.

range(5)          # 0, 1, 2, 3, 4
range(1, 11)      # 1 … 10
range(0, 60, 5)   # 0, 5, 10 … 55  (step 5)
range(10, 0, -1)  # 10, 9, 8 … 1

Lists

Ordered, mutable, allow duplicates. The most common container.

processes = ["chrome", "electron", "python", "java"]

# Indexing & slicing
processes[0]      # 'chrome'
processes[-1]     # 'java'
processes[1:3]    # ['electron', 'python']

# Common list methods
processes.append("vscode")           # add to end
processes.insert(1, "slack")         # insert at index
processes.remove("java")             # remove by value
processes.pop()                      # remove and return last
processes.pop(0)                     # remove and return at index
processes.sort()                     # sort in-place (alphabetical)
processes.reverse()                  # reverse in-place
len(processes)                       # count items
"chrome" in processes                # True

Building a snapshot list

ram_history = []
for _ in range(10):
    ram_history.append(get_ram_pct())
# [72.1, 73.5, 74.0, 74.3, 73.9, ...]

Tuples

Ordered, immutable, allow duplicates. Use for records that should not change.

snapshot = ("chrome", 4821, 1024.5, 73.5)
#            name     pid   rss_mb  pct

proc_name, pid, rss_mb, pct = snapshot   # unpacking

# Named access by index
print(snapshot[0])   # 'chrome'

Tuples are faster than lists and signal “this data is a fixed record.”


Sets

Unordered, no duplicates, mutable. Perfect for tracking unique process names.

seen_procs = {"chrome", "electron", "python"}
seen_procs.add("vscode")
seen_procs.discard("java")        # safe remove — no error if absent

# Set operations
morning = {"chrome", "vscode", "python"}
evening = {"chrome", "slack", "python"}

morning & evening   # {'chrome', 'python'}   intersection
morning | evening   # all unique names        union
morning - evening   # {'vscode'}              difference
morning ^ evening   # {'vscode', 'slack'}     symmetric difference

Dicts

Key-value pairs, ordered (Python 3.7+), mutable. The RAM manager’s core: {pid: snapshot_data}.

proc_map = {
    4821: {"name": "chrome",   "rss_mb": 1024.5, "pct": 73.5},
    312:  {"name": "kernel",   "rss_mb": 128.0,  "pct": 0.9},
    9001: {"name": "electron", "rss_mb": 512.0,  "pct": 36.7},
}

# Access
proc_map[4821]["name"]          # 'chrome'
proc_map.get(9999, "unknown")   # 'unknown' — safe default if key missing

# Iteration
for pid, info in proc_map.items():
    print(f"PID {pid}: {info['name']}  {info['rss_mb']:.1f} MB")

# Modification
proc_map[4821]["rss_mb"] = 1100.0

# Keys, values, items
list(proc_map.keys())    # [4821, 312, 9001]
list(proc_map.values())  # [{'name': 'chrome', ...}, ...]

Nested Data

Combine lists, dicts, and tuples to model complex state.

history = {
    "chrome": [1024, 1050, 1100, 1090],   # RSS over time
    "electron": [512, 520, 530],
}

# Access nested value
history["chrome"][-1]   # 1090 — most recent snapshot

loop-else

The else clause on a loop runs only when the loop was not terminated by break.

critical_pid = None
for pid, info in proc_map.items():
    if info["pct"] > 90:
        critical_pid = pid
        break
else:
    print("No critical processes found in this snapshot")

Iteration Helpers

processes = ["chrome", "electron", "python"]
rss_list  = [1024.5,   512.0,     64.0]

# enumerate — index + value
for i, name in enumerate(processes, start=1):
    print(f"{i}. {name}")

# zip — pair two iterables
for name, rss in zip(processes, rss_list):
    print(f"{name}: {rss} MB")

Data Structure Comparison

flowchart LR
    A[Data Structures] --> B[list]
    A --> C[tuple]
    A --> D[set]
    A --> E[dict]
    B --> F["Ordered, mutable, duplicates OK"]
    C --> G["Ordered, immutable, duplicates OK"]
    D --> H["Unordered, mutable, NO duplicates"]
    E --> I["Key-value, ordered keys, mutable"]

RAM Manager State Model

flowchart TD
    A[proc_map dict] --> B["pid: int → keys"]
    B --> C["name: str"]
    B --> D["rss_mb: float"]
    B --> E["pct: float"]
    A --> F[seen_procs set]
    F --> G["unique names — no duplicates"]
    A --> H[ram_history list]
    H --> I["snapshots over time — ordered"]
    A --> J[snapshot tuple]
    J --> K["fixed record — name, pid, rss, pct"]

Key Takeaways

  • Lists are ordered and mutable — use them for time-series RAM snapshots.
  • Tuples are immutable records — use them for a single process snapshot that should not change.
  • Sets automatically deduplicate — ideal for tracking which process names have been seen.
  • Dicts map keys to values — {pid: info_dict} is the natural shape of the RAM manager’s process table.
  • enumerate() gives index + value; zip() pairs two iterables — both avoid manual index tracking.
  • loop-else runs only when a loop completes without break — useful for “not found” logic.
  • Nest lists, dicts, and tuples freely to model hierarchical system data.