Skip to content
ExamSpine

Lesson 5.19

Capstone: read record lines, split, report

Part 5: Text, lists, stacks and queuesReading, about 7 min1 exercise in this lesson

Java answers can't run on Spine yet. You can still read Java, trace it, and put an answer's lines in order.

Read records and split each line into fields

By the end of this you will be able to read a set of records one line at a time, split each line into its fields, keep the fields in lists, and go back over the lists to answer questions that need every record.

This lesson puts Part 5 together. A record is one line of data about one thing, such as one sale in a shop. Its fields are the parts of the line, with a separator between them. You already know each piece: splitting a line, turning text into a number, adding to a list, accumulating, and searching. Here they become one program.

The plan in one picture

Most programs that read records have the same shape. Read how many records there are, then loop: read a line, split it, and keep or add up what you need. When the loop ends, every record has been seen, and the program can answer questions about all of them.

StartInput ni = 0i < n?Input one record lineSplit it at the commasKeep the fields; add upi = i + 1Go through the lists againOutput the reportStop yesno

The loop runs once for each record. The box after the loop, going through the lists again, is there only when a question needs a value that is not known until the last record has been read. You will see one below.

One record, split

A shop writes each sale as the item, how many were sold, and the price of one, in whole dollars. Here is what happens to the line pen,3,5 when it is split at the commas:

the line         pen,3,5
split at ","     pen   3   5
position         0     1   2

The positions are fixed: 0 is always the item, 1 the quantity and 2 the price. That is what makes a record easy to use. Give each field a name as soon as you split it, and turn the numbers from text into whole numbers before you do any sums with them. The cost of this sale is 3 times 5, which is 15.

The task

The program reads the number of sales (1 to 50), then one sale per line. Each quantity is from 1 to 20 and each price from 1 to 100. It prints the day's takings, the biggest single sale, and every item that made a sale of exactly that size.

The last question is the one that needs the lists. While the loop is running, the biggest sale so far can still be beaten by a later one, so the program cannot yet say which items made the biggest sale. It keeps every item and every cost, and looks again once the loop is over.

The program

n = int(input())
items = []
costs = []
takings = 0
biggest = 0
for i in range(n):
    parts = input().split(",")
    item = parts[0]
    cost = int(parts[1]) * int(parts[2])
    items.append(item)
    costs.append(cost)
    takings = takings + cost
    if cost > biggest:
        biggest = cost
best = []
for i in range(n):
    if costs[i] == biggest:
        best.append(items[i])
print("Takings: " + str(takings))
print("Biggest sale: " + str(biggest))
print("Items: " + ", ".join(best))
import java.util.ArrayList;
import java.util.Scanner;

public static void main(String[] args) {
    Scanner scanner
        = new Scanner(System.in);
    int n = Integer.parseInt(
        scanner.nextLine());
    ArrayList<String> items =
        new ArrayList<>();
    ArrayList<Integer> costs =
        new ArrayList<>();
    int takings = 0;
    int biggest = 0;
    for (int i = 0; i < n; i++) {
        String line = scanner.nextLine();
        String[] parts = line.split(",");
        String item = parts[0];
        int cost =
            Integer.parseInt(parts[1])
            * Integer.parseInt(parts[2]);
        items.add(item);
        costs.add(cost);
        takings = takings + cost;
        if (cost > biggest) {
            biggest = cost;
        }
    }
    ArrayList<String> best =
        new ArrayList<>();
    for (int i = 0; i < n; i++) {
        if (costs.get(i) == biggest) {
            best.add(items.get(i));
        }
    }
    System.out.println(
        "Takings: " + takings);
    System.out.println(
        "Biggest sale: " + biggest);
    System.out.println(
        "Items: " + String.join(", ", best));
}

If the user types 4, then pen,3,5, bag,1,15, cap,2,6 and mug,4,2, the program prints:

Takings: 50
Biggest sale: 15
Items: pen, bag

What the lists hold

When the first loop ends, the two lists look like this:

position   0     1     2     3
items      pen   bag   cap   mug
costs      15    15    12    8

Each record is added to both lists on the same turn, so the item and the cost of one sale sit at the same position. That is why the second loop goes through the positions rather than the values: costs at position 1 is 15, so items at position 1, bag, is one of the answers.

The first loop does two jobs you know from earlier lessons. It accumulates, adding every cost to takings, and it keeps a biggest so far. The biggest so far can start at 0 here, because every sale is worth at least 1, so the first sale always beats it. The second loop is a search that keeps going to the end, because more than one item can share the biggest sale.

Two common slips

  • Deciding too early. Suppose the first loop added an item to best whenever its cost was the biggest so far. With the sales mug,4,2 and then pen,3,5, the mug's 8 is the biggest so far when it is read, so mug would be listed, even though the pen's 15 beats it a moment later. A question about the biggest, or the average, of all the records can only be answered once every record is in.
  • Doing sums with the text. Every part of a split line is text. In Python, parts[1] * parts[2] stops the program with an error, because two text values cannot be multiplied. In Java, the same line does not compile. Turn each number into a whole number first, as the program does with int in Python and Integer.parseInt in Java.

The pattern to remember

Read a record, split it, name its fields, and convert the numbers. Keep what later questions need in lists that line up by position, and add up what you can as you go. When a question needs every record, answer it in a second loop over the lists. Now try it yourself on the questions below.

Exercise 5.19.15.19.1 · Write itSports day report

Write a program that reads the results of a sports day, one record per line, and prints a short report.

  1. The first line is the name of one house, typed in any mix of capital and small letters, for example red.
  2. The second line is the number of records, a whole number from 1 to 50.
  3. Each record is one line: a name, a house and a score, separated by commas with no spaces around them. For example: Mei Lin,Red,88. A name can have spaces in it but no commas. A house is one word. A score is a whole number from 0 to 100.
  4. Print House total: and the scores of every record whose house is the house from the first line added up. Capital letters do not matter when matching: red, Red and RED are the same house. If no record matches, the total is 0.
  5. Print Average: and the average of all the scores, as a whole number (drop the fraction).
  6. Print Above average: and the names of everyone whose score is above that whole-number average, in the order they were read, with a comma and a space between names. If nobody is above it, print Above average: none.
  7. Print Top: , the name with the highest score, with , and that score. If two or more share the highest score, give the one read first.

For the first example below, the program prints:

House total: 160
Average: 63
Above average: Ana, Mei Lin
Top: Mei Lin with 88

Your program is run several times. Only what it prints is checked.

Running Java here comes later. You can put this answer's lines in order instead. You can still write your Java answer (it stays while this page is open) and compare it with our worked solution. Or try this exercise in Python.

Examples

Your program is run 8 times: the 3 examples below, and 5 hidden ones that check the rules above. Only what it prints is checked.

  • the example: the house typed in small letters, two names above average (rules 4, 5, 6, 7)

    You type

    1. typed: red
    2. typed: 4
    3. typed: Ana,Red,72
    4. typed: Leo,Blue,55
    5. typed: Mei Lin,Red,88
    6. typed: Sam,Green,40

    It prints

    House total: 160
    Average: 63
    Above average: Ana, Mei Lin
    Top: Mei Lin with 88
  • two records share the top score, and the one read first is given (rule 7)

    You type

    1. typed: Blue
    2. typed: 3
    3. typed: Kofi,Blue,90
    4. typed: Ines,Green,90
    5. typed: Tom,Blue,30

    It prints

    House total: 120
    Average: 70
    Above average: Kofi, Ines
    Top: Kofi with 90
  • every score equals the average, so nobody is above it (rule 6)

    You type

    1. typed: GREEN
    2. typed: 2
    3. typed: Ravi,Green,50
    4. typed: Zoe,Red,50

    It prints

    House total: 50
    Average: 50
    Above average: none
    Top: Ravi with 50
solution.pySolution.java