Matua Doc

Matua Doc

Solution: Swift programming revision for Level 3

Sample answer (Swift)

  • This is one complete working solution that matches the requirements in the revision task.
  • It uses a for loop, a while loop, if statements, and functions.

Full program

This section will not display correctly in presentation mode. Please press Esc to return to web page view.

import Foundation

/// Formats a `Double` as currency with exactly two decimal places.
/// - Parameter value: The numeric value to format.
/// - Returns: A string like `$6.50`.
func money(_ value: Double) -> String {
    "$" + String(format: "%.2f", value)
}

/// Returns the total (sum) of all prices in the array.
/// - Parameter prices: A list of lunch prices.
/// - Returns: The sum of all values in `prices`.
func totalCost(prices: [Double]) -> Double {
    prices.reduce(0, +)
}

/// Returns the average (mean) value of the prices.
/// - Parameter prices: A list of lunch prices.
/// - Returns: The mean of `prices`, or `0` if the array is empty.
func averageCost(prices: [Double]) -> Double {
    guard !prices.isEmpty else { return 0 }
    return totalCost(prices: prices) / Double(prices.count)
}

/// Checks if the total spending is over the given budget.
/// - Parameters:
///   - total: The total amount spent.
///   - budget: The maximum allowed budget.
/// - Returns: `true` when `total` is greater than `budget`.
func isOverBudget(total: Double, budget: Double) -> Bool {
    total > budget
}

/// Finds the most expensive lunch cost.
/// - Parameter prices: A list of lunch prices.
/// - Returns: The maximum value in `prices`, or `0` if the array is empty.
func mostExpensiveDay(prices: [Double]) -> Double {
    prices.max() ?? 0
}

@main
struct SwiftPlayground {
    /// Program entry point (typical Swift Package / SPM style).
    static func main() {
        // Input data: lunch costs for Monday to Friday.
        // Double is used because money values can include decimals.
        let lunches = [6.50, 8.00, 5.75, 9.20, 7.10]

        // The weekly budget is a constant because it does not change.
        let budget = 35.00

        // Part 2 + Part 5
        // A for loop is used to process each day’s lunch cost.
        // enumerated() provides both the index (0...4) and the price.
        for (index, price) in lunches.enumerated() {
            // Convert the zero-based index into a human-friendly day number (1...5).
            let dayNumber = index + 1
            print("Day \(dayNumber): \(money(price))")

            // Part 5: check each day’s lunch as we loop.
            // This condition runs once per lunch value.
            if price > 9.00 {
                print("High spending day detected.")
            }
        }

        // Part 6
        // Use a while loop because we don’t know in advance how many snacks
        // it will take to reach at least $10.
        let snackCost = 2.50
        var snackTotal = 0.0

        // Keep buying snacks until the total reaches the target.
        while snackTotal < 10.0 {
            snackTotal += snackCost
            print("Snack total: \(money(snackTotal))")
        }

        // Part 4 + Part 7
        // Calculate totals once and store them in named constants.
        // This improves readability and avoids repeating calculations.
        let lunchTotal = totalCost(prices: lunches)
        let combinedTotal = lunchTotal + snackTotal
        let averageLunch = averageCost(prices: lunches)

        // Print the final summary in the requested format.
        print("Lunch total: \(money(lunchTotal))")
        print("Snack total: \(money(snackTotal))")
        print("Combined total: \(money(combinedTotal))")
        print("Average lunch cost: \(money(averageLunch))")

        // Part 4: choose the correct message using an if statement.
        // The boolean function keeps the condition clear and testable.
        if isOverBudget(total: lunchTotal, budget: budget) {
            print("Warning: You overspent this week.")
        } else {
            print("You stayed within budget.")
        }

        // Extension output: show the most expensive lunch cost.
        print("Most expensive lunch: \(money(mostExpensiveDay(prices: lunches)))")
    }
}

Breakdown: Data set-up

let lunches = [6.50, 8.00, 5.75, 9.20, 7.10]
let budget = 35.00
  • lunches is a [Double] because the prices include decimals.
  • budget is a constant (let) because it is a fixed comparison value for the week.

Breakdown: Money formatting

/// Formats a Double as $0.00
func money(_ value: Double) -> String {
    "$" + String(format: "%.2f", value)
}
  • The task examples show money with exactly two decimal places, so this helper function makes printing consistent everywhere.
  • Putting formatting in one function avoids repeating the same formatting logic in multiple print statements.

Breakdown: Required functions (totals, average, budget)

func totalCost(prices: [Double]) -> Double {
    prices.reduce(0, +)
}

func averageCost(prices: [Double]) -> Double {
    guard !prices.isEmpty else { return 0 }
    return totalCost(prices: prices) / Double(prices.count)
}

func isOverBudget(total: Double, budget: Double) -> Bool {
    total > budget
}
  • totalCost uses reduce because it is the clearest way to add all values in an array.
  • averageCost uses guard to prevent division by zero, then divides by the number of days.
  • isOverBudget returns a boolean so the final if statement reads clearly.

Breakdown: For loop (print each day)

for (index, price) in lunches.enumerated() {
    let dayNumber = index + 1
    print("Day \(dayNumber): \(money(price))")
}
  • enumerated() provides both the index and the value, which is useful for producing “Day 1 … Day 5”.
  • Adding 1 converts the zero-based index into a human-friendly day number.

Breakdown: If inside the loop (high spending day)

if price > 9.00 {
    print("High spending day detected.")
}
  • This if is inside the loop so it runs once per day and can detect any lunch over $9.00.
  • It prints immediately when the condition is met, matching the task requirement.

Breakdown: While loop (snack simulation)

let snackCost = 2.50
var snackTotal = 0.0

while snackTotal < 10.0 {
    snackTotal += snackCost
    print("Snack total: \(money(snackTotal))")
}
  • A while loop is appropriate because you don’t know ahead of time how many snacks are needed to reach $10.
  • The running total is printed each iteration to show the accumulation step-by-step.

Breakdown: Final summary + budget decision

let lunchTotal = totalCost(prices: lunches)
let combinedTotal = lunchTotal + snackTotal
let averageLunch = averageCost(prices: lunches)

print("Lunch total: \(money(lunchTotal))")
print("Snack total: \(money(snackTotal))")
print("Combined total: \(money(combinedTotal))")
print("Average lunch cost: \(money(averageLunch))")

if isOverBudget(total: lunchTotal, budget: budget) {
    print("Warning: You overspent this week.")
} else {
    print("You stayed within budget.")
}
  • Totals are calculated once and stored in named constants so the summary prints are easy to read.
  • The budget message uses an if statement driven by the boolean function, keeping the comparison logic separate from the output.

Breakdown: Extension (most expensive lunch)

func mostExpensiveDay(prices: [Double]) -> Double {
    prices.max() ?? 0
}

print("Most expensive lunch: \(money(mostExpensiveDay(prices: lunches)))")
  • max() directly finds the largest value in the array, which matches “most expensive”.
  • ?? 0 provides a safe default if the array were empty, so the function always returns a Double.