COMPUTER PROGRAMMING 1 (JAVASCRIPT) • CORE DATA STRUCTURES

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

Learn to build new arrays by looping through existing ones—transforming and filtering data one element at a time.

Historical Context & Motivation

Every app you use daily—from social media feeds to music playlists—works by taking large collections of data and reshaping them for display. A photo app might shrink all your images to thumbnails; a search engine filters millions of results to show only the relevant ones. At the core of these operations is a simple idea: loop through a list, and build a new list that contains only the items (or transformed versions of items) you actually need.

This pattern is one of the oldest and most universal ideas in programming. Long before JavaScript existed, programmers in languages like FORTRAN and LISP were iterating over arrays and constructing new ones. The pattern has survived because it solves a problem that never goes away: raw data rarely looks the way we want it to, so we must transform values into a useful form and filter out the noise.

1957
FORTRAN & DO Loops
IBM's FORTRAN introduced the DO loop, giving programmers a structured way to iterate over arrays of numbers for scientific computation.
1958
LISP & List Processing
John McCarthy created LISP, a language built around transforming and filtering lists—the intellectual ancestor of JavaScript's array methods.
1995
JavaScript Is Born
Brendan Eich designed JavaScript with C-style for loops, making array iteration accessible in web browsers for the first time.
2009
ES5 Adds forEach, map, filter
ECMAScript 5 introduced built-in higher-order methods, but understanding the underlying loop pattern remains essential for every developer.

The central question this lesson addresses is straightforward: given an existing array, how do you use a loop to produce a brand-new array that contains either modified versions of the original elements (transformation) or only those elements that meet a specific condition (filtering)? Mastering this loop-based pattern gives you the foundation for every data-processing task you will encounter.

Core Principles & Definitions

Before diving into code, let's nail down the vocabulary you'll use throughout this lesson and beyond. Two operations sit at the heart of array processing: transforming (changing every element in some way) and filtering (keeping only the elements that pass a test). Both operations share a common structure: start with an empty result array, loop through the source, and push items into the result.

1

Source Array

The original array you read from. It is never modified—you treat it as read-only so the original data stays intact.
2

Result Array

A new, initially empty array that you build up inside the loop using push(). When the loop ends, this array holds your output.
3

Transform Pattern

Loop through every element, apply a change (e.g., multiply by 2, convert to uppercase), and push the changed value into the result array.
4

Filter Pattern

Loop through every element, check a condition with an if statement, and push only the elements that pass the test.
5

Immutability Mindset

Building a new array instead of changing the original is safer and more predictable. Other parts of your program that reference the source array are unaffected.
✦ KEY TAKEAWAY
Think of a conveyor belt at a factory. The source array is the raw material rolling along the belt. A transform is a machine that reshapes every item (like stamping each piece of metal into a gear). A filter is a quality inspector who only lets the good parts through. In both cases, the conveyor belt (source) keeps moving untouched—you collect the output in a separate bin (result array).

Visual Explanation — The Loop-Based Build Pattern

The following diagram shows how the transform pattern works step by step. The source array [2, 5, 8] is processed by a for loop that doubles each value and pushes it into a new result array. Follow the numbered steps from left to right to see how the result array grows with each iteration.

Each iteration reads one element from the source, doubles it, and pushes the result into a new array. After all three iterations, the result array [4, 10, 16] is complete, while the source [2, 5, 8] remains untouched.

Notice the three-part structure that stays the same every time you use this pattern. First, you declare an empty result array before the loop. Second, inside the loop body you compute a new value (or check a condition). Third, you push() the new value into the result. This three-step rhythm is the backbone of both transforming and filtering.

How It Works — Code Patterns in Detail

The Transform Pattern

The transform pattern visits every element in the source array, applies some operation, and pushes the modified value into the result. Here is the general template:

TRANSFORM TEMPLATE
const result = []; for (let i = 0; i < source.length; i++) { const newValue = transform(source[i]); result.push(newValue); }
source — the original array. transform() — any expression that converts the current element to its new form. result — the new array that accumulates transformed values.

The Filter Pattern

The filter pattern also visits every element, but instead of transforming it, the loop checks a boolean condition. Only elements that satisfy the condition are pushed into the result.

FILTER TEMPLATE
const result = []; for (let i = 0; i < source.length; i++) { if (condition(source[i])) { result.push(source[i]); } }
condition() — a boolean expression (e.g., source[i] > 10). Only elements where this is true make it into the result.

Combining Transform + Filter

You can combine both patterns in a single loop. For example, you might want to double only the even numbers in an array. In that case, you place the if check first, and inside the if block you transform and push. This shows the real power of understanding the loop-based approach: you can mix and match however your problem demands.

COMBINED TEMPLATE
const result = []; for (let i = 0; i < source.length; i++) { if (source[i] % 2 === 0) { result.push(source[i] * 2); } }
This loop filters for even numbers (% 2 === 0) and doubles them in one pass. The result contains only the doubled even values.

Detailed Breakdown — Transform vs. Filter Side by Side

The diagram below places the transform and filter patterns side by side so you can see exactly where they differ. Both start with the same source array [3, 7, 12, 4, 18]. The left branch transforms every element (adds 10), while the right branch filters for elements greater than 5. Pay attention to the result array sizes—transforms always produce the same number of elements, while filters may produce fewer.

The transform branch (left, pink) always produces a result with the same number of elements as the source. The filter branch (right, cyan) may produce fewer elements because items that fail the condition are skipped.
Key differences between transform and filter patterns
FeatureTransformFilter
PurposeChange every elementKeep only elements that pass a test
Result lengthSame as source≤ source length
Uses if statement?No (every element is pushed)Yes (only matching elements)
Element valuesDifferent from sourceIdentical to source

Worked Example — Building a Filtered & Transformed Array

Suppose you have an array of student test scores and you need to produce a new array that contains only the passing scores (70 or above), each converted to a letter grade. This combines both filtering and transforming in a single loop.

Filtering Passing Scores & Converting to Letter Grades
1
Step 1 — Identify the Source ArrayStart with the scores array: const scores = [88, 42, 95, 67, 73, 58, 100]; This is our source—we will not change it.
2
Step 2 — Create an Empty Result ArrayDeclare the result: const passingGrades = []; This starts empty and will grow inside the loop.
3
Step 3 — Write the Loop with Filter + TransformLoop through every score. Inside the loop, check if the score is ≥ 70 (filter). If it passes, convert the number to a letter grade (transform) and push the grade into the result. for (let i = 0; i < scores.length; i++) { if (scores[i] >= 70) { let grade; if (scores[i] >= 90) { grade = 'A'; } else if (scores[i] >= 80) { grade = 'B'; } else { grade = 'C'; } passingGrades.push(grade); } }
4
Step 4 — Trace Through Each Iterationi=0: 88 ≥ 70? Yes → 88 ≥ 90? No → 88 ≥ 80? Yes → push 'B'. i=1: 42 ≥ 70? No → skip. i=2: 95 ≥ 70? Yes → 95 ≥ 90? Yes → push 'A'. i=3: 67 ≥ 70? No → skip. i=4: 73 ≥ 70? Yes → 73 ≥ 90? No → 73 ≥ 80? No → push 'C'. i=5: 58 ≥ 70? No → skip. i=6: 100 ≥ 70? Yes → 100 ≥ 90? Yes → push 'A'.
5
Step 5 — Read the ResultAfter the loop completes, passingGrades contains the final result.
["B", "A", "C", "A"] — four passing grades from seven original scores. The source array scores is unchanged.
⚠️ Common Mistake
Forgetting to create the empty result array before the loop is the most common error. If you write const result = []; inside the loop, the array resets to empty on every iteration and you'll end up with only the last item!

Strengths, Limitations & When to Use Each Pattern

The loop-based build pattern is extremely flexible, but like any tool it comes with trade-offs. Understanding these will help you decide when to use a manual loop and when a built-in method might be more appropriate.

Strengths and limitations of the loop-based build pattern
AspectStrengthLimitation
FlexibilityYou can combine filter + transform + any custom logic in a single loopMore lines of code than built-in methods like .map() or .filter()
ReadabilityEasy to trace step by step; great for learningCan become lengthy for simple operations
PerformanceSlightly faster than chaining multiple built-in methodsPerformance difference is negligible for most high school projects
SafetyBuilds a new array—original data stays intactIf you accidentally modify source[i] (an object), the original mutates too
DebuggingYou can add console.log inside the loop to inspect each stepOff-by-one errors (wrong loop bounds) are a common pitfall
✦ KEY TAKEAWAY
Think of the loop-based pattern as driving a manual-transmission car: you control every gear shift, which means more work but also more control. Built-in methods like .map() and .filter() are like an automatic transmission—convenient, but they only do what they're designed for. Learning the manual approach first ensures you truly understand what's happening under the hood.

Connection to Built-In Methods & Advanced Patterns

Once you're confident with loop-based patterns, you'll be ready to use JavaScript's higher-order array methods. These methods do the same work as the patterns you've learned, but they express it more concisely. The table below shows the direct relationship between each loop pattern and its built-in counterpart.

Loop patterns map directly to built-in methods
Loop-Based PatternBuilt-In MethodWhat It Does
Transform with for loop.map(callback)Returns a new array with each element transformed by the callback
Filter with for loop + if.filter(callback)Returns a new array with only elements where callback returns true
Accumulate to single value.reduce(callback, init)Reduces the array to a single value (sum, count, object, etc.)
Check every element.every(callback)Returns true only if every element passes the test

When you eventually write const doubled = nums.map(n => n * 2);, you'll understand that JavaScript is running a loop behind the scenes, creating an empty array, pushing transformed values, and returning the result—exactly the pattern you've practiced in this lesson. That deep understanding is what separates a programmer who uses tools from one who truly understands them.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Explain in your own words why we create an empty result array before the loop, rather than inside it. What would happen if you placed const result = []; inside the loop body?
PROBLEM 2 — BASIC CALCULATION
Given const temps = [32, 68, 95, 50, 77]; (Fahrenheit), write a loop that builds a new array called celsius containing each temperature converted to Celsius. Use the formula C = (F − 32) × 5 / 9, rounded to one decimal place.
PROBLEM 3 — INTERMEDIATE
Given const words = ["apple", "Banana", "cherry", "Date", "elderberry"];, write a loop that builds a new array containing only the words that start with a lowercase letter, and converts each of those words to uppercase.
PROBLEM 4 — APPLIED
You are building a simple online store. You have an array of product objects: const products = [{name: "Notebook", price: 3.50}, {name: "Pen", price: 1.25}, {name: "Backpack", price: 45.00}, {name: "Eraser", price: 0.75}, {name: "Calculator", price: 12.99}]; Write a loop that builds a new array of strings for items under $5.00. Each string should read like: "Notebook - $3.50".
PROBLEM 5 — CRITICAL THINKING
A classmate writes this code to get only the even numbers from an array, but it doesn't work correctly. Find the bug, explain why it causes a problem, and fix it: const nums = [4, 9, 12, 7, 6]; const evens = []; for (let i = 1; i <= nums.length; i++) { if (nums[i] % 2 === 0) { evens.push(nums[i]); } }

Lesson Summary

In this lesson you learned the fundamental loop-based build pattern for creating new arrays from existing ones. The pattern has three consistent steps: declare an empty result array before the loop, iterate through the source array with a for loop, and push values into the result. When you change each element before pushing, you are transforming; when you use an if statement to decide whether to push, you are filtering.

Key ideas to remember: transforms always produce a result array of the same length as the source, while filters may produce a shorter array. You can combine both patterns in a single loop for more complex tasks. The source array is never modified, keeping your data safe. This loop-based approach is the foundation for understanding JavaScript's built-in methods like .map() and .filter(), which you'll learn next.

Varsity Tutors • Computer Programming 1 (JavaScript) • Transforming & Filtering Arrays