Sensor Reading Cleanup and Summary

EE1021 Programming for Engineers · Lecture 4 Lab · 2026–2027

Basri Erdogan

Lab Outcomes

By the end of the lab, you should be able to:

  1. Inspect, index, slice, and update a list of measurements
  2. Choose correctly among append, extend, insert, remove, and pop
  3. Build a filtered list with a comprehension
  4. Return a tuple from a function and unpack its results
  5. Demonstrate the difference between an alias and a clone
  6. Explain one list mutation during an individual checkoff

Working Method

For every stage:

  1. Predict the important result before typing.
  2. Implement the smallest working step.
  3. Run and compare actual with predicted behavior.
  4. Explain one correction in a comment.
  5. Rotate roles: the navigator becomes the driver.

Open starter/lecture4_lab.py and keep its function names unchanged.

Pre-Lab Diagnostic

Answer without running Python:

values = [1, 2]
values.append([3, 4])
print(values)
  1. What is printed?
  2. Which method would add 3 and 4 as separate elements?
  3. Does append return the changed list?

Check: [1, 2, [3, 4]]; use extend; append mutates the list and returns None.

Stage 1: Inspect and Correct Data

Task 1: Inspect the Readings

The starter contains:

raw_readings = [4.91, 4.96, -1.0, 5.08, 5.72]

Print:

  • the first and last readings;
  • the middle three readings using one slice;
  • the number of readings.

Record the four predicted results in comments before running.

Task 2: Correct and Extend

Perform these operations without rewriting the complete list:

  1. Replace -1.0 with 4.99 by index.
  2. Insert 5.01 immediately before the final reading.
  3. Append 4.93.
  4. Extend the list with [5.03, 4.89].

Print the list after each operation. Identify which operations add one element and which can add several.

Check-Off A: Method Semantics

Show your partner, then the instructor if requested:

  • one indexed replacement;
  • one insert operation;
  • the different results of append([1, 2]) and extend([1, 2]);
  • one sentence explaining why append returns None.

Stage 2: Validate Measurements

Task 3: Classify One Reading

Complete:

def is_valid_voltage(value, low=4.75, high=5.25):
    """Return True when value is inside the inclusive valid range."""
    pass

Required boundary tests:

Input Expected
4.74 False
4.75 True
5.25 True
5.26 False

Task 4: Filter with a Comprehension

Use is_valid_voltage inside a comprehension:

valid_readings = ...  # replace with a comprehension

Requirements:

  • preserve the order of valid readings;
  • do not mutate raw_readings;
  • print raw_readings and valid_readings;
  • print how many readings were rejected.

Debugging Checkpoint

A student wrote:

valid_readings = [is_valid_voltage(value) for value in raw_readings]

Why does this produce Booleans instead of voltage values? Rewrite it so the expression produces each valid value and the condition filters.

valid_readings = [value for value in raw_readings
                  if is_valid_voltage(value)]

Stage 3: Summarize the Data

Task 5: Return a Summary Tuple

Complete:

def summarize_readings(readings):
    """Return (minimum, maximum, average) for a non-empty list."""
    pass

Do not print inside the function. In the main program:

minimum, maximum, average = summarize_readings(valid_readings)

Display the three results rounded to two decimal places.

Test the Function Independently

Before using experimental data, verify a case with an obvious result:

test = [1.0, 2.0, 3.0]

Expected tuple: (1.0, 3.0, 2.0).

Explain why testing a small known case can reveal an error before the full workflow runs.

Task 6: Build Sample Records

Pair each sensor ID with one reading using tuples:

sensor_ids = ["S1", "S2", "S3"]
readings = [4.92, 5.08, 4.97]

samples = []
for i in range(len(sensor_ids)):
    samples.append((sensor_ids[i], readings[i]))

Iterate over samples using tuple unpacking and print one report line per sensor.

Stage 4: Investigate References

Task 7: Alias Experiment

Run one line at a time and record each prediction first.

original = [4.92, 5.08]
alias = original
alias.append(4.97)

print(original)
print(alias)

Draw arrows from the two names to the list objects that exist after assignment.

Task 8: Clone Experiment

clone = original.copy()
clone.append(5.01)

print(original)
print(clone)

Answer in comments:

  1. Which operation created a new outer list?
  2. Why is 5.01 absent from original?
  3. What does shallow copy mean for a list containing inner lists?

Stage 5: Integrate and Check Off

Final Workflow

Complete the starter so it:

  1. keeps raw_readings unchanged during filtering;
  2. builds valid_readings with a comprehension;
  3. returns and unpacks a summary tuple;
  4. prints a concise report;
  5. demonstrates aliasing and cloning in separate variables;
  6. passes every supplied assertion.

Individual Checkoff

Each student must complete one randomly selected action without partner help:

  • change append to extend and predict the structural difference;
  • remove one reading by index and capture its value;
  • write or repair the filtering comprehension;
  • explain an alias diagram after one mutation;
  • make summarize_readings return a tuple and unpack it.

Use checkoff_rubric.qmd to see the criteria.

Exit Ticket

Submit three sentences or code fragments:

  1. One list operation that mutates and one that creates a new list.
  2. A comprehension that keeps only positive values from data.
  3. Why changing an alias can change the original list.