Computer Programming 1 (Python) • Core Data Structures

Transforming & Filtering Lists — I can transform/filter a list using loop-based patterns (build a new list) at my level.

Learn to build new lists by looping through existing ones, selecting and reshaping data along the way.

A Python coding terminal with a program flow and laptop.
Inside this lesson 10 sections 5 questions 8 figures

SECTION 1

Historical Context & Motivation

Since the earliest days of computing, programmers have needed to take collections of data and produce new collections from them. Imagine a teacher who has a gradebook full of raw scores and needs a separate list of only the passing grades, or a game developer who has a list of all player positions and needs to extract only the ones inside a certain zone. These tasks — transforming data (changing every item) and filtering data (keeping only items that meet a condition) — are two of the most common operations in all of programming.

1958 • LISP Introduces map & filter

John McCarthy's LISP language formalized the idea of applying a function to every element in a list (map) and keeping only elements that pass a test (filter). These concepts became foundational in computer science.

1991 • Python Is Born

Guido van Rossum released Python, emphasizing readability. Python's for loops made iterating through lists intuitive, even for beginners.

2000 • List Comprehensions Added to Python

Python 2.0 introduced list comprehensions — a compact syntax inspired by mathematical set notation. However, the underlying loop-based pattern remains the clearest way for beginners to learn the concept.

Today • Data Pipelines Everywhere

Modern applications — from social media feeds to scientific data analysis — constantly transform and filter massive lists. Mastering loop-based patterns gives you the mental model behind all of these tools.

The central question this lesson addresses is straightforward: How do you take an existing list and produce a brand-new list that contains only the items you want, possibly changed in some way? The answer lies in a simple, repeatable loop pattern that you can use for almost any list-processing task.

SECTION 2

Core Principles & Definitions

Before diving into code, let's pin down the key ideas. Every transform-or-filter task follows the same three-part recipe: start with a source list, loop through it, and build a result list. Understanding these principles will make writing the code feel automatic.

1

The Accumulator Pattern

Create an empty list before the loop. Inside the loop, append() items to it. After the loop, the new list holds your results.
2

Transforming (Mapping)

Apply some operation to each item — for example, doubling every number or converting every string to uppercase — and add the changed item to the new list.
3

Filtering (Selecting)

Use an if statement inside the loop to test each item. Only append items that pass the condition.
4

Transform + Filter Combined

You can filter first and then transform, or do both at once inside the same loop. This is incredibly common in real programs.
5

Non-Destructive Processing

Building a new list means the original list stays unchanged. This is important because other parts of your program may still need the original data.
✦

KEY TAKEAWAY

Think of the accumulator pattern like packing a suitcase for a trip. You start with an empty suitcase (the new list). You look at every item in your closet (the source list). For each item, you decide whether it goes in the suitcase and maybe fold it differently (transform). When you're done, you have a packed suitcase — a new, purpose-built collection — and your closet is untouched.

SECTION 3

Visual Explanation — The Accumulator Loop

Filtering Pattern: Keep Only Even NumbersSource list:3811256for num in numbers:if num % 2 == 0:Is the number even?YESNO → skipresult.append(num)→ next iterationResult list:8126Original list [3, 8, 1, 12, 5, 6] is unchanged
The diagram shows the filtering pattern. Each element of the source list is tested by the if condition. Only elements that pass (the even numbers 8, 12, and 6) are appended to the result list. The original list remains untouched.

Notice the three stages in the diagram above. First, the source list feeds items one at a time into the loop. Second, the if condition acts as a gate, letting some items through and blocking others. Third, the items that pass are collected in the result list via append(). This three-stage structure is the same whether you're filtering numbers, strings, or any other data type.

SECTION 4

How It Works — The Code Patterns

Pattern 1: Transform Every Item

When you want to transform every item in a list (also called mapping), you apply an operation to each element and store the result. The skeleton looks like this:

TRANSFORM PATTERN

result=[]foriteminsource:result.append(f(item))result = [] for item in source: result.append( f(item) )

Where source is the original list, item is each element in turn, and f(item) is whatever operation you perform (e.g., item * 2 or item.upper()).

Pattern 2: Filter Items by Condition

When you want to filter a list, you include an if statement inside the loop. Only items that satisfy the condition are appended.

FILTER PATTERN

result=[]foriteminsource:ifcondition(item):result.append(item)result = [] for item in source: if condition(item): result.append(item)

Where condition(item) is a Boolean expression, such as item > 0 or len(item) >= 5.

Pattern 3: Filter + Transform Combined

FILTER + TRANSFORM PATTERN

result=[]foriteminsource:ifcondition(item):result.append(f(item))result = [] for item in source: if condition(item): result.append( f(item) )

First test, then transform. This way the new list contains only the items you want, already in their new form.

⚠

Common Mistake

Don't forget to create the empty list before the loop! If you write result = [] inside the loop, it resets on every iteration and you'll end up with only the last item.

SECTION 5

Patterns in Action — Real Code Examples

Transform Pattern: Double Every Priceprices = [9.99, 24.50, 3.75, 15.00]doubled = []CODE — before the loopLOOP: for p in prices:p = 9.99→ 19.98p = 24.50→ 49.00p = 3.75→ 7.50p = 15.00→ 30.00doubled.append(p * 2)Each price is multipliedby 2 and added to thenew list.doubled → [19.98, 49.00, 7.50, 30.00]RESULT — new list with transformed valuesOriginal list prices = [9.99, 24.50, 3.75, 15.00] is still intact — non-destructive!
This diagram traces a transform loop that doubles each price. Each iteration takes one value from prices, multiplies it by 2, and appends the result to doubled. The original list stays untouched.

Let's see the full Python code for both a transform and a filter example. Study the structure carefully — the skeleton is the same every time.

Transform ExampleFilter Example
names = ["alice", "bob", "cara"] upper_names = [] for n in names: upper_names.append(n.upper()) # ["ALICE", "BOB", "CARA"]scores = [88, 42, 95, 67, 73] passing = [] for s in scores: if s >= 70: passing.append(s) # [88, 95, 73]

Side-by-side comparison of the transform and filter patterns

In the transform example on the left, every name is converted to uppercase and placed in the new list. In the filter example on the right, only scores of 70 or above make it into passing. The key difference is the presence or absence of an if statement inside the loop.

SECTION 6

Worked Example — Filter & Transform a Grade List

Suppose you have a list of student percentages and you need to produce a new list containing only the grades above 60, converted to letter grades using a simple rule: 90+ → 'A', 80–89 → 'B', 70–79 → 'C', 60–69 → 'D'. Let's walk through the full solution.

Build a List of Passing Letter Grades

  1. 1

    Step 1 — Define the source data

    We start with a list of raw percentages: grades = [92, 55, 78, 83, 41, 67, 95]. This is our source list that we will loop through.
  2. 2

    Step 2 — Create the empty result list

    Before the loop, initialize the accumulator: letter_grades = []. This list will hold only passing letter grades.
    letter_grades = []
  3. 3

    Step 3 — Write the loop with the filter condition

    We iterate with for g in grades: and immediately check if g > 60:. This filters out the failing scores (55 and 41).
  4. 4

    Step 4 — Transform passing scores to letters

    Inside the if block, we use if/elif to convert the numeric grade to a letter. For example, 92 becomes 'A', 78 becomes 'C', and 67 becomes 'D'. We then append the letter to letter_grades.
  5. 5

    Step 5 — Verify the result

    After the loop completes, print(letter_grades) outputs the final list. The original grades list is unchanged.
    ["A", "C", "B", "D", "A"] — only the 5 passing grades, converted to letters
💡

Full Code

grades = [92, 55, 78, 83, 41, 67, 95] letter_grades = [] for g in grades: if g > 60: if g >= 90: letter_grades.append("A") elif g >= 80: letter_grades.append("B") elif g >= 70: letter_grades.append("C") else: letter_grades.append("D") print(letter_grades) # ["A", "C", "B", "D", "A"]

SECTION 7

Strengths & Limitations of Loop-Based Patterns

The loop-based accumulator pattern is a powerful tool, but like any technique, it has trade-offs. Understanding when it shines and when alternatives might be better will make you a more thoughtful programmer.

Strengths ✅Limitations ⚠️
Easy to read and understand — the logic flows line by line.Can be verbose for simple operations (more lines of code than a list comprehension).
Fully flexible — you can combine filtering, transforming, and complex logic in one loop.For very large data sets, Python loops can be slow compared to built-in functions optimized in C.
Easy to debug — you can add print statements inside the loop to inspect each iteration.If you accidentally modify the source list instead of building a new one, bugs can be hard to track down.
Works with any iterable, not just lists — strings, files, ranges, and more.Experienced Python developers often prefer list comprehensions for brevity, so you'll need to learn those too.

Strengths and limitations of the loop-based accumulator pattern

✦

KEY TAKEAWAY

The loop-based pattern is like a manual transmission in a car — it gives you full control over every gear shift, making it perfect for learning. List comprehensions and built-in functions like map() and filter() are like automatic transmission — faster to use once you understand what's happening under the hood. Master the manual version first.

SECTION 8

Connection to List Comprehensions & Beyond

Once you're comfortable with loop-based patterns, you'll be ready to learn list comprehensions — Python's compact, one-line way to do the same thing. A list comprehension packs the loop, the condition, and the transformation into a single expression. Understanding the loop pattern first makes comprehensions feel natural rather than magical.

Loop-Based Pattern (This Lesson)List Comprehension (Next Step)
result = [] for x in nums: result.append(x * 2)result = [x * 2 for x in nums]
result = [] for x in nums: if x > 0: result.append(x)result = [x for x in nums if x > 0]
Multiple lines, easy to debug, great for complex logicOne line, concise, Pythonic — best for simple transforms/filters

Side-by-side: loop patterns vs. list comprehensions

Beyond list comprehensions, Python offers built-in functions like map() and filter(), as well as powerful libraries like pandas for data science. All of these higher-level tools do the same fundamental thing your loop does: iterate over a collection, optionally test each item, optionally transform it, and collect the results. The pattern you learned today is the foundation for all of them.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

In your own words, explain why we create an empty list before the loop instead of inside it. What would happen if we placed result = [] inside the for loop?
Show answer
If you place result = [] inside the loop, the list is reset to empty on every iteration. This means each pass through the loop wipes out everything that was previously appended. After the loop finishes, result would contain only the last item processed (if it was appended) or would be empty. By creating the list before the loop, we ensure that append() accumulates values across all iterations.

Question 2: BASIC CALCULATION

Given temps_f = [32, 68, 212, 98.6, 50], write a loop that builds a new list temps_c containing each temperature converted to Celsius using the formula C = (F − 32) × 5 / 9. What does temps_c contain?
Show answer
The code is: temps_c = [] followed by for f in temps_f: and temps_c.append((f - 32) * 5 / 9). Each Fahrenheit value is transformed: 32°F → 0.0°C, 68°F → 20.0°C, 212°F → 100.0°C, 98.6°F → 37.0°C, and 50°F → 10.0°C. The result is [0.0, 20.0, 100.0, 37.0, 10.0]. This is a pure transform pattern — no filtering needed since every temperature is converted.

Question 3: INTERMEDIATE

Given words = ["hello", "I", "am", "a", "Python", "programmer"], write a loop that builds a new list long_upper containing only the words with 4 or more characters, converted to uppercase. What is the output?
Show answer
This combines filtering and transforming. The code is: long_upper = [], then for w in words: with if len(w) >= 4: and long_upper.append(w.upper()). The filter condition len(w) >= 4 eliminates "I", "am", and "a". The remaining words are transformed to uppercase: "hello" → "HELLO", "Python" → "PYTHON", "programmer" → "PROGRAMMER". The final result is ["HELLO", "PYTHON", "PROGRAMMER"].

Question 4: APPLIED

A school stores student data as a list of lists: students = [["Ana", 91], ["Ben", 64], ["Cho", 88], ["Dex", 55], ["Eva", 76]]. Write a loop that builds a new list honor_roll containing only the names (not scores) of students who scored 80 or above.
Show answer
The solution is: honor_roll = [], then for student in students: with if student[1] >= 80: and honor_roll.append(student[0]). Here student[1] accesses the score for filtering, and student[0] accesses the name for the result. Ana (91) and Cho (88) qualify, so honor_roll becomes ["Ana", "Cho"]. This demonstrates that you can filter on one part of the data and collect a different part.

Question 5: CRITICAL THINKING

A classmate writes this code to remove negative numbers from a list: nums = [3, -1, 4, -5, 2] followed by for n in nums: and if n < 0: nums.remove(n). They report that it sometimes misses negative numbers. Explain why this approach is buggy and how building a new list solves the problem.
Show answer
Modifying a list while iterating over it is a classic Python pitfall. When nums.remove(n) removes an element, the remaining elements shift left, but the loop's internal index still advances. This causes the loop to skip the element that slid into the position of the removed item. For example, after removing −1 at index 1, the value 4 shifts from index 2 to index 1, but the loop moves to index 2, which is now −5. If two negatives are adjacent, one will be skipped. The correct approach is the accumulator pattern: positives = [], for n in nums: if n >= 0: positives.append(n). Building a new list avoids mutating the collection you're iterating over, eliminating the bug entirely.

SUMMARY

Lesson Summary

Summary

In this lesson you learned the accumulator pattern — a reliable recipe for building a new list from an existing one. The pattern has three steps: create an empty result list before the loop, iterate through the source list with a for loop, and use append() to add items to the result. For transforming, you modify each item before appending. For filtering, you use an if statement to decide which items make the cut. You can combine both in a single loop.

This pattern is non-destructive — the original list remains intact, which prevents subtle bugs caused by modifying data in place. As you advance, you'll see that list comprehensions and built-in functions like map() and filter() are shorthand for the exact same loop-based logic. Mastering the explicit loop first gives you the foundation to understand — and debug — every future tool you encounter.

Varsity Tutors • Computer Programming 1 (Python) • Transforming & Filtering Lists