Records
Grouping related fields: a sensor reading as a record, and a list of records as a table.
Do this lesson in the simulatorA distance reading on its own is only a number. It becomes information when you also know which way the robot was facing and when it was taken. A record groups related values of different kinds under one name, each value in a named field. A list of records is a table: each record is a row, each field a column.
A record as a dictionary
Python's most common way to write a record is a dictionary: fields named by strings, in curly brackets:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
reading = {"heading": 0, "distance": distance(), "battery": battery()}
print(reading)
print("facing", reading["heading"], "the wall is", reading["distance"], "cm away")
reading["note"] = "first look" # add a field
reading["heading"] = 90 # change a field
print(reading)
A field is reached by its name in square brackets, reading["distance"], where a list would use a number. The fields hold different types here: an integer, a real, and later a string. That mix is what makes a record different from an array.
A list of records
One record per reading, collected in a list, gives a table:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
log = []
for i in range(4):
log.append({"look": i + 1, "heading": i * 90, "distance": distance()})
turn_right(30, angle=90)
for r in log:
print(f"look {r['look']}: facing {r['heading']}, {r['distance']} cm")
| look | heading | distance |
|---|---|---|
| 1 | 0 | ... |
| 2 | 90 | ... |
| 3 | 180 | ... |
| 4 | 270 | ... |
Inside an f-string that already uses double quotes, the field names go in single quotes: r['heading'].
Searching a table of records
The patterns you know work on records: go through the list and look at one field:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
log = [
{"heading": 0, "distance": 31.0},
{"heading": 90, "distance": 51.0},
{"heading": 180, "distance": 15.0},
{"heading": 270, "distance": 31.0},
]
closest = log[0]
for r in log:
if r["distance"] < closest["distance"]:
closest = r
print("closest wall is at heading", closest["heading"], closest["distance"], "cm")
for r in log:
if r["distance"] > 30:
print("room to drive at heading", r["heading"])
Keeping the whole record as closest, not only the distance, means the heading comes with it for free.
Records as their own type
A dictionary does not stop you misspelling a field name. For bigger programs Python can define a record type with fixed fields, a dataclass:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
from dataclasses import dataclass
@dataclass
class Reading:
heading: int
distance: float
r = Reading(90, distance())
print(r)
print(r.heading, r.distance)
The fields are listed once, with their types, and reached with a dot. This is close to how exam pseudo-code writes records. Either form is fine for this module.
Task: reading records
The robot is boxed in on three sides. Look in four directions, 90 degrees apart, storing each look as a record with the fields heading and distance in a list. Then print one line per record as heading 0: 31.0 cm, and finally print closest heading: <heading> for the record with the smallest distance.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
log = []
for i in range(4):
turn_right(30, angle=90)
Challenges
- Add a
timefield to each record usingclock(). - Print the log as a table, with the headings lined up using f-string widths like
{r['distance']:6}. - Store three names and scores as records and print the name with the highest score.