Computer Programming 1 (JavaScript) • Problem Solving & Mini-Projects

Transforming Datasets — I can transform a dataset (filter, map fields) and output results in a readable report.

Learn to filter, reshape, and display data using JavaScript's powerful array methods.

A JavaScript data file with code brackets and a laptop.
Inside this lesson 10 sections 5 questions 8 figures

SECTION 1

Historical Context & Motivation

Computers have always been about processing data — taking raw information, sifting through it, and presenting something useful. Before programming languages existed, people performed these tasks by hand: clerks would sort through paper records, pick out relevant entries, copy specific columns into a new ledger, and write up a summary report. The entire field of data transformation grew from the need to automate this tedious but essential work.

As programming languages evolved, developers created increasingly elegant ways to express these operations. JavaScript, originally designed for simple web page interactions in the mid-1990s, eventually gained powerful array methods that made data transformation concise and readable. Understanding the history of these tools helps you appreciate why modern JavaScript code for filtering and mapping looks the way it does.

1958 • Lisp Introduces map and filter

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

1995 • JavaScript Is Born

Brendan Eich created JavaScript in ten days at Netscape. Early versions had basic array support but lacked the built-in transformation methods we use today.

2009 • ES5 Adds .filter() and .map()

ECMAScript 5 standardized .filter() and .map() as built-in array methods, giving every JavaScript developer easy access to functional-style data transformation.

2015 • ES6 Arrow Functions

Arrow functions (=>) made chaining .filter() and .map() calls much more concise and readable, fueling the modern JavaScript style.

2020s • Data Pipelines Everywhere

Today, transforming datasets is a core pattern in web apps, APIs, dashboards, and data science. JavaScript's array methods power millions of real-time interfaces that filter and display data from databases and APIs.

The central question this lesson addresses is straightforward: given an array of objects (a dataset), how do you select only the items you want, reshape each item to contain only the fields you need, and then produce a nicely formatted output? By the end of this lesson, you will be able to chain .filter() and .map() together and output a readable report to the console.

SECTION 2

Core Principles & Definitions

Before diving into code, let's nail down the core ideas. A dataset in JavaScript is typically an array of objects, where each object represents one record — like one student, one product, or one game score. Transforming a dataset means taking that array and producing a new array (or a formatted string) that contains only the information you care about.

1

Dataset (Array of Objects)

A collection of records stored as an array. Each element is an object with key-value pairs representing fields like name, age, or score.
2

Filter (.filter())

A method that creates a new array containing only the elements that pass a test (a callback function that returns true or false).
3

Map (.map())

A method that creates a new array by applying a transformation function to every element. Use it to reshape objects — picking specific fields or computing new ones.
4

Chaining

Because both .filter() and .map() return new arrays, you can chain them: data.filter(...).map(...). This is a clean, readable pipeline.
5

Readable Report

The final step: formatting your transformed data into a human-friendly string or console output using template literals, console.table(), or a .join() call.
✦

KEY TAKEAWAY

Think of a dataset transformation like a cafeteria lunch line. Filter is the step where you skip the foods you don't want — you only grab what matches your criteria. Map is putting each chosen item on your tray in a specific arrangement — maybe you only take the fruit off the plate and leave the garnish behind. The report is you describing your tray to a friend in a clear sentence. The original buffet stays untouched — you always get a new tray.
💡

Non-Destructive Operations

Both .filter() and .map() are non-destructive — they never modify the original array. They always return a brand-new array. This means your source data stays safe no matter how many transformations you apply.

SECTION 3

Visual Explanation — The Data Pipeline

The diagram below shows the flow of data through a typical filter-then-map pipeline. On the left you see the original dataset — five student records. The filter stage removes records that don't meet the condition (grade below 80), leaving three students. The map stage then reshapes each surviving record, extracting only the name and grade fields. Finally, the report presents the result as formatted text.

Original DataAli 92 ABo 67 CCam 85 BDee 73 CEve 91 A.filter()grade >= 80✓ Ali (92)✗ Bo (67)✓ Cam (85)✗ Dee (73).map()pick name & grade{ name: Ali, grade: 92 }{ name: Cam, grade: 85 }{ name: Eve, grade: 91 }ReportHonor Roll:- Ali: 92- Cam: 85- Eve: 913 students total5 records in → 3 pass test3 records reshapedFormatted outputCode equivalent:const honorRoll = students .filter(s => s.grade >= 80) .map(s => ({ name: s.name, grade: s.grade }))const report = honorRoll .map(s => `- ${s.name}: ${s.grade}`).join('\n')
Data flows left to right: the original five-record dataset enters the filter stage (cyan), which removes records below 80. Survivors pass to the map stage (violet), which extracts only the desired fields. The result is formatted into a readable report (green).

Notice two important things in the diagram. First, the original dataset on the left is never modified — every stage produces a new array. Second, the .filter() callback returns true or false for each element (shown as ✓ and ✗), while the .map() callback returns a brand-new object for each element. This distinction is crucial: filter decides which items survive, and map decides what shape each surviving item takes.

SECTION 4

How .filter() and .map() Work Under the Hood

Understanding the internal mechanics of .filter() and .map() makes the syntax click. Both methods follow the same basic pattern: iterate over every element in the array, call a callback function on each element, and use the callback's return value to build a new array. The difference is what each method does with the return value.

The .filter() Method

When you call array.filter(callback), JavaScript creates an empty result array, then loops through each element. For each element, it calls your callback. If the callback returns a truthy value, the element is pushed into the result array. If the callback returns a falsy value, the element is skipped. The method then returns the result array.

FILTER PATTERN

array.filter(element=>condition)array.filter(element => condition)

element — each item in the array, one at a time. condition — a boolean expression. If true, the element is included in the new array. The original array is untouched.

The .map() Method

When you call array.map(callback), JavaScript creates an empty result array, loops through each element, calls your callback, and pushes whatever the callback returns into the result array. This is how you reshape data: your callback receives the old object and returns a new one with different fields, computed values, or formatted strings.

MAP PATTERN

array.map(element=>newValue)array.map(element => newValue)

element — each item, one at a time. newValue — any expression. The result array will contain these new values in the same order. The result array always has the same length as the original.

Chaining: Filter Then Map

CHAIN PATTERN

array.filter(condition).map(transform)array.filter(condition).map(transform)

First, .filter() produces a shorter array. Then .map() reshapes each remaining element. The chain reads like an English sentence: "Take my array, keep only items where condition is true, then transform each one."

⚠

Order Matters

Always filter before you map when the filter condition uses fields that the map might remove. If you map first and strip out a field, you can no longer filter on it. Think of it like choosing which apples to keep before peeling them — you want to inspect them while they still have their skin.

SECTION 5

Syntax Deep Dive — Callbacks, Arrow Functions & Template Literals

To use .filter() and .map() effectively, you need to be comfortable with three JavaScript features: callback functions, arrow function syntax, and template literals for building readable output. This section breaks each one down.

Arrow Function Anatomyconst result = students.filter(s => s.grade >= 80)parametereach elementarrow"goes to"condition / bodyreturns true or falseTemplate Literal for Reports`${s.name} scored ${s.grade} points`backtick `starts the literal${...}expression slot${...}second slotbacktick `ends the literalOutput:Ali scored 92 points
Top: The anatomy of an arrow function used with .filter(). The parameter (s) represents each element; the arrow (=>) leads to the body. Bottom: A template literal with backticks and ${} slots for embedding expressions directly into strings.
Syntax FeatureWhat It Looks LikeWhen to Use It
Regular functionfunction(s) { return s.grade >= 80; }When you want maximum clarity or need the this keyword.
Arrow function (concise)s => s.grade >= 80Single expression that returns a value — the most common form in filter/map.
Arrow function (block body)s => { const x = s.grade; return x >= 80; }When you need multiple statements inside the callback. Must include return explicitly.
Template literal`Name: ${s.name}`Building readable output strings with embedded variables — perfect for reports.
.join(separator)lines.join('\n')Combining an array of strings into one string with a separator between each element.

Key syntax features used when building data transformation pipelines

SECTION 6

Worked Example — Building an Honor Roll Report

Let's walk through a complete example. Imagine you have a dataset of students, and you need to produce a report listing only students with grades of 80 or above, showing each student's name and grade in a clean, readable format.

Honor Roll Report

  1. 1

    Step 1 — Define the Dataset

    Start by creating an array of student objects. Each object has three fields: name, grade, and club. const students = [ { name: "Ali", grade: 92, club: "Chess" }, { name: "Bo", grade: 67, club: "Art" }, { name: "Cam", grade: 85, club: "Drama" }, { name: "Dee", grade: 73, club: "Chess" }, { name: "Eve", grade: 91, club: "Band" } ];
    5 student objects stored in students
  2. 2

    Step 2 — Filter for Honor Roll (grade ≥ 80)

    Use .filter() with a callback that checks if the student's grade is 80 or higher. This returns a new array containing only qualifying students. const honorStudents = students.filter(s => s.grade >= 80);
    Result: [{ name: "Ali", grade: 92, club: "Chess" }, { name: "Cam", grade: 85, club: "Drama" }, { name: "Eve", grade: 91, club: "Band" }] — 3 of 5 students pass the test.
  3. 3

    Step 3 — Map to Extract Name and Grade Only

    The report doesn't need the club field. Use .map() to create new objects with only name and grade. const reportData = honorStudents.map(s => ({ name: s.name, grade: s.grade }));
    Result: [{ name: "Ali", grade: 92 }, { name: "Cam", grade: 85 }, { name: "Eve", grade: 91 }]
  4. 4

    Step 4 — Format as Readable Lines

    Use .map() a second time to convert each object into a formatted string using a template literal. const lines = reportData.map(s => ` - ${s.name}: ${s.grade}`);
    Result: [" - Ali: 92", " - Cam: 85", " - Eve: 91"]
  5. 5

    Step 5 — Combine and Output the Report

    Join the lines into a single string with newlines and add a header. Then log it to the console. const report = `Honor Roll Report\n${lines.join('\n')}\n\nTotal: ${lines.length} students`; console.log(report);
    Console output: Honor Roll Report - Ali: 92 - Cam: 85 - Eve: 91 Total: 3 students
💡

Chaining All at Once

You can combine Steps 2–4 into one chained expression for a cleaner look: const lines = students .filter(s => s.grade >= 80) .map(s => ` - ${s.name}: ${s.grade}`); This does filtering and formatting in a single pipeline. Each method returns a new array, so the chain flows naturally from one step to the next.

SECTION 7

filter/map vs. Other Approaches

You might wonder: can't you just use a for loop to do the same thing? Absolutely — but there are trade-offs. Understanding when to use .filter() and .map() versus a traditional loop or other methods will help you write cleaner, more maintainable code.

ApproachStrengthsLimitations
.filter() + .map()Declarative and readable — each method has one job. Non-destructive. Easy to chain. Encourages clean, small callbacks.Iterates through the array twice (once for filter, once for map). Slightly less efficient on very large datasets (millions of items).
for loopFull control over iteration. Can filter and map in a single pass. Familiar to beginners.More verbose — requires manual array creation, pushing, and index management. Easier to introduce bugs.
.forEach()Runs a function on each element. Good for side effects like logging.Does not return a new array. You must manually push to an external array, which is less clean.
.reduce()Can do everything — filter, map, and accumulate — in a single pass.Harder to read, especially for beginners. Overkill for simple filter + map tasks.

Comparing approaches for dataset transformation

✦

KEY TAKEAWAY

Use .filter() and .map() as your default approach for transforming datasets. Think of them as specialized tools in a toolbox: a wrench and a screwdriver each do one thing well, and using the right tool for each job makes your work clearer than a single Swiss Army knife (.reduce()) that tries to do everything at once. Switch to a for loop only when performance is critical or you need complex control flow.

SECTION 8

Connection to Advanced Patterns

The filter-map-report pattern you've learned is the foundation of much more powerful data processing techniques. As you advance in programming, you'll encounter these same ideas applied at a much larger scale — in databases, APIs, and real-time applications.

What You Learned TodayAdvanced Version
.filter() on an arrayWHERE clauses in SQL databases — same concept, different syntax
.map() to reshape objectsSELECT statements in SQL — choosing which columns to return
Chaining .filter().map()Functional programming pipelines in libraries like RxJS or data tools like Pandas (Python)
Console report with console.log()Rendering data in HTML tables, charts, or dashboards using React, Vue, or D3.js
Hardcoded dataset in your codeFetching live data from an API with fetch() and transforming the JSON response

How today's skills connect to advanced programming patterns

You'll also encounter .sort() for ordering results, .reduce() for computing totals and averages, and .find() for locating a single record. These all follow the same callback pattern you've practiced here, so picking them up later will feel natural. The mental model of "pass a function to describe what I want" is the single most important idea to carry forward.

SECTION 9

Practice Problems

Work through the following five problems to solidify your understanding of filtering, mapping, and report generation. Each problem builds on the skills from the lesson.

Question 1: CONCEPTUAL

Explain in your own words: why does .filter() return a new array instead of modifying the original? What advantage does this give you as a programmer?
Show answer
The .filter() method returns a new array to preserve the original data — this is called being non-destructive. The advantage is that you can apply multiple different filters to the same dataset without worrying about one transformation interfering with another. For example, you could filter students by grade for one report and filter the same array by club for a different report, and the original students array remains unchanged throughout. This makes your code safer, easier to debug, and more predictable.

Question 2: BASIC CALCULATION

Given the array const prices = [12, 5, 8, 25, 3, 18];, write a .filter() call that returns only prices above 10. What is the resulting array?
Show answer
The code is: const expensive = prices.filter(p => p > 10);. The callback p => p > 10 checks each price. The values 12, 25, and 18 are all greater than 10, so the result is [12, 25, 18]. The values 5, 8, and 3 fail the test and are excluded. The original prices array is unchanged.

Question 3: INTERMEDIATE

Given const books = [ { title: "1984", pages: 328, genre: "fiction" }, { title: "Cosmos", pages: 365, genre: "science" }, { title: "Dune", pages: 412, genre: "fiction" }, { title: "Brief History", pages: 256, genre: "science" } ];, write a chain that filters for science books and maps each to a string in the format "Title (X pages)". What does the final array look like?
Show answer
The code is: const scienceList = books .filter(b => b.genre === "science") .map(b => `${b.title} (${b.pages} pages)`);. First, .filter() keeps only the two science books (Cosmos and Brief History). Then .map() transforms each remaining object into a formatted string using a template literal. The result is ["Cosmos (365 pages)", "Brief History (256 pages)"]. Notice we chained the methods — the output of filter flows directly into map.

Question 4: APPLIED

You have a dataset of products: const products = [ { name: "Laptop", price: 999, inStock: true }, { name: "Mouse", price: 25, inStock: false }, { name: "Monitor", price: 350, inStock: true }, { name: "Keyboard", price: 75, inStock: true }, { name: "Webcam", price: 60, inStock: false } ];. Write code that: (1) filters for products that are in stock, (2) maps each to an object with only name and a new field priceLabel formatted as "$999", and (3) outputs a multi-line report to the console.
Show answer
Here is the complete solution: const available = products .filter(p => p.inStock) .map(p => ({ name: p.name, priceLabel: `$${p.price}` })); const report = available .map(p => ` ${p.name} — ${p.priceLabel}`) .join('\n'); console.log(`Available Products:\n${report}\n\n${available.length} items in stock`); The filter keeps Laptop, Monitor, and Keyboard (all have inStock: true). The first map creates new objects with a formatted price. The second map converts each to a string line, and .join('\n') merges them with newlines. The output reads: "Available Products: Laptop — $999 Monitor — $350 Keyboard — $75 3 items in stock".

Question 5: CRITICAL THINKING

A classmate writes the following code and complains that the filter doesn't work — it returns an empty array even though some games have ratings above 4. Can you find and explain the bug? const games = [ { title: "Zelda", rating: 4.8 }, { title: "Mario", rating: 4.5 }, { title: "Pong", rating: 3.2 } ]; const topGames = games .map(g => g.title) .filter(g => g.rating > 4);
Show answer
The bug is that .map() is called before .filter(). The .map(g => g.title) transforms each object into just a string (e.g., "Zelda"). By the time .filter() runs, g is a string, not an object, so g.rating is undefined, and undefined > 4 is false for every element. The fix is to swap the order: games.filter(g => g.rating > 4).map(g => g.title). This filters while the objects still have the rating field, then maps to extract titles.

SUMMARY

Lesson Summary

Summary

In this lesson you learned how to transform a dataset — an array of objects — using JavaScript's built-in array methods. The .filter() method accepts a callback that returns true or false and produces a new array containing only the elements that passed the test. The .map() method accepts a callback that transforms each element and returns a new array of the same length. Both methods are non-destructive — the original array is never modified.

By chaining these methods — data.filter(...).map(...) — you can build clean data pipelines that select, reshape, and format records in a readable way. To produce a readable report, use template literals with backticks and ${} expression slots, then combine lines with .join('\n'). Remember the golden rule: always filter before you map when the filter condition depends on fields that the map might remove. These skills form the foundation for database queries, API data handling, and front-end rendering that you'll encounter as you advance in programming.

Varsity Tutors • Computer Programming 1 (JavaScript) • Transforming Datasets — I can transform a dataset (filter, map fields) and output results in a readable report.