I own a parking lot that can hold up to 'n' cars at any given point in time. Each slot is given a number starting at 1 increasing with increasing distance from the entry point in steps of one. I want to create an automated ticketing system that allows my customers to use my parking lot without human intervention.
When a car enters my parking lot, I want to have a ticket issued to the driver. The ticket issuing process includes us documenting the registration number (number plate) and the colour of the car and allocating an available parking slot to the car before actually handing over a ticket to the driver (we assume that our customers are nice enough to always park in the slots allocated to them). The customer should be allocated a parking slot which is nearest to the entry. At the exit the customer returns the ticket which then marks the slot they were using as being available.
Due to government regulation, the system should provide me with the ability to find out:
●くろまる Registration numbers of all cars of a particular colour.
●くろまる Slot number in which a car with a given registration number is parked.
●くろまる Slot numbers of all slots where a car of a particular colour is parked.
import heapq
from collections import defaultdict, OrderedDict
class Car:
def __init__(self, registration_number, color):
self.registration_number = registration_number
self.color = color
def __str__(self):
return "Car [registration_number=" + self.registration_number + ", color=" + self.color + "]"
class ParkingLot:
def __init__(self, total_slots):
self.registration_slot_mapping = dict()
self.color_registration_mapping = defaultdict(list)
# we need to maintain the orders of cars while showing 'status'
self.slot_car_mapping = OrderedDict()
# initialize all slots as free
self.available_parking_lots = []
# Using min heap as this will always give minimun slot number in O(1) time
for i in range(1, total_slots + 1):
heapq.heappush(self.available_parking_lots, i)
def status(self):
for slot, car in self.slot_car_mapping.items():
print("Slot no: {} {}".format(slot, car))
def get_nearest_slot(self):
return heapq.heappop(self.available_parking_lots) if self.available_parking_lots else None
def free_slot(self, slot_to_be_freed):
found = None
for registration_no, slot in self.registration_slot_mapping.items():
if slot == slot_to_be_freed:
found = registration_no
# Cleanup from all cache
if found:
del self.registration_slot_mapping[found]
car_to_leave = self.slot_car_mapping[slot_to_be_freed]
self.color_registration_mapping[car_to_leave.color].remove(found)
del self.slot_car_mapping[slot_to_be_freed]
print("leave ", slot_to_be_freed)
else:
print("slot is not in use")
def park_car(self, car):
slot_no = self.get_nearest_slot()
if slot_no is None:
print("Sorry, parking lot is full")
return
self.slot_car_mapping[slot_no] = car
self.registration_slot_mapping[car.registration_number] = slot_no
self.color_registration_mapping[car.color].append(car.registration_number)
# ●くろまる Registration numbers of all cars of a particular colour.
def get_registration_nos_by_color(self, color):
return self.color_registration_mapping[color]
# ●くろまる Slot numbers of all slots where a car of a particular colour is parked.
def get_slot_numbers_by_color(self, color):
return [self.registration_slot_mapping[reg_no] for reg_no in self.color_registration_mapping[color]]
if __name__ == "__main__":
parking_lot = ParkingLot(6)
print(parking_lot.available_parking_lots)
car = Car("KA-01-HH-1234", "White")
parking_lot.park_car(car)
car = Car("KA-01-HH-9999", "White")
parking_lot.park_car(car)
car = Car("KA-01-BB-0001", "Black")
parking_lot.park_car(car)
car = Car("KA-01-HH-7777", "Red")
parking_lot.park_car(car)
car = Car("KA-01-HH-2701", "Blue")
parking_lot.park_car(car)
car = Car("KA-01-HH-3141", "Black")
parking_lot.park_car(car)
# When no slots are available then
slot_no = parking_lot.get_nearest_slot()
print(slot_no)
slot_no = parking_lot.get_nearest_slot()
print(slot_no)
# Leave slot no 4
slot_no_to_be_freed = 4
parking_lot.free_slot(slot_no_to_be_freed)
heapq.heappush(parking_lot.available_parking_lots, 4)
car = Car("KA-01-P-333", "White")
parking_lot.park_car(car)
car = Car("DL-12-AA-9999", "White")
parking_lot.park_car(car)
parking_lot.status()
print(parking_lot.available_parking_lots)
print(parking_lot.registration_slot_mapping)
print(parking_lot.color_registration_mapping)
registration_numbers = parking_lot.get_registration_nos_by_color('White')
print("White : {}".format(registration_numbers))
registration_numbers = parking_lot.get_registration_nos_by_color('Red')
print("Red : {}".format(registration_numbers))
registration_numbers = parking_lot.get_registration_nos_by_color('Black')
print("Black : {}".format(registration_numbers))
slot_nos = parking_lot.get_slot_numbers_by_color('White')
print("White : {}".format(slot_nos))
slot_nos = parking_lot.get_slot_numbers_by_color('Red')
print("Red : {}".format(slot_nos))
slot_nos = parking_lot.get_slot_numbers_by_color('Black')
print("Black : {}".format(slot_nos))
parking_lot.status()
parking_lot.free_slot(1)
parking_lot.free_slot(2)
parking_lot.free_slot(3)
parking_lot.status()
2 Answers 2
This seems horribly overcomplex, and you don't provide a reason why.
A data structure that associates an increasing integer value (starting at 1) with an object of some type would be a list
(an array
in other languages). Normally they start at zero, but you can fix that pretty quickly by stuffing a dummy value in the l[0]
slot.
Making that change would touch just about every part of your ParkingLot
class, so I'll ignore the rest of it.
Given how simple the Car
class is, I suggest you replace it with a collections.namedtuple
instead.
-
\$\begingroup\$ Actually this was requirement from some client. and they wanted parking slots to be human readable like staring from 1. If I start from 0 then I have make changes at all retrieval levels. \$\endgroup\$Girish Gupta– Girish Gupta2019年08月02日 04:23:29 +00:00Commented Aug 2, 2019 at 4:23
I have divided this program into multiple files as per below:
|____ __init__.py
|____ parking_lot.py
|____ test.py
|____ process_input.py
|____ commands.txt
parking_lot.py is my main module.
#parking_lot.py
import heapq
from collections import defaultdict, OrderedDict
class Car:
def __init__(self, registration_number, color):
self.registration_number = registration_number
self.color = color
def __str__(self):
return "Car [registration_number=" + self.registration_number + ", color=" + self.color + "]"
class ParkingLot:
def __init__(self):
self.registration_slot_mapping = dict()
self.color_registration_mapping = defaultdict(list)
# we need to maintain the orders of cars while showing 'status'
self.slot_car_mapping = OrderedDict()
# initialize all slots as free
self.available_parking_lots = []
def create_parking_lot(self, total_slots):
# Using min heap as this will always give minimum slot number in O(1) time
print("Created a parking lot with {} slots".format(total_slots))
for i in range(1, total_slots + 1):
heapq.heappush(self.available_parking_lots, i)
return True
def status(self):
print("Slot No. Registration No Colour")
for slot, car in self.slot_car_mapping.items():
print("{} {} {}".format(slot, car.registration_number, car.color))
return True
def get_nearest_slot(self):
return heapq.heappop(self.available_parking_lots) if self.available_parking_lots else None
def leave(self, slot_to_be_freed):
found = None
for registration_no, slot in self.registration_slot_mapping.items():
if slot == slot_to_be_freed:
found = registration_no
# Cleanup from all cache
if found:
heapq.heappush(self.available_parking_lots, slot_to_be_freed)
del self.registration_slot_mapping[found]
car_to_leave = self.slot_car_mapping[slot_to_be_freed]
self.color_registration_mapping[car_to_leave.color].remove(found)
del self.slot_car_mapping[slot_to_be_freed]
print("Slot number {} is free".format(slot_to_be_freed))
return True
else:
print("slot is not in use")
return False
def park(self, car):
slot_no = self.get_nearest_slot()
if slot_no is None:
print("Sorry, parking lot is full")
return
print("Allocated slot number: {}".format(slot_no))
self.slot_car_mapping[slot_no] = car
self.registration_slot_mapping[car.registration_number] = slot_no
self.color_registration_mapping[car.color].append(car.registration_number)
return slot_no
# Registration numbers of all cars of a particular colour
def registration_numbers_for_cars_with_colour(self, color):
registration_numbers = self.color_registration_mapping[color]
print(", ".join(registration_numbers))
return self.color_registration_mapping[color]
# Slot numbers of all slots where a car of a particular colour is parked
def slot_numbers_for_cars_with_colour(self, color):
registration_numbers = self.color_registration_mapping[color]
slots = [self.registration_slot_mapping[reg_no] for reg_no in registration_numbers]
print(", ".join(map(str, slots)))
return slots
def slot_number_for_registration_number(self, registration_number):
slot_number = None
if registration_number in self.registration_slot_mapping:
slot_number = self.registration_slot_mapping[registration_number]
print(slot_number)
return slot_number
else:
print("Not found")
return slot_number
this test.py covers different test scenarios.
from parking_lot import ParkingLot, Car
parking_lot = ParkingLot()
cars = [
Car('KA-01-HH-1234', 'White'),
Car('KA-01-HH-9999', 'White'),
Car('KA-01-BB-0001', 'Black'),
Car('KA-01-HH-7777', 'Red'),
Car('KA-01-HH-2701', 'Blue'),
Car('KA-01-HH-3141', 'Black'),
]
assert parking_lot.create_parking_lot(6) is True
for i in range(0, len(cars)):
assert parking_lot.park(cars[i]) == i + 1
assert parking_lot.leave(4) is True
assert parking_lot.status() is True
assert len(parking_lot.available_parking_lots) == 1
assert parking_lot.park(Car('KA-01-P-333', 'White')) == 4
assert parking_lot.registration_numbers_for_cars_with_colour('White') == ['KA-01-HH-1234', 'KA-01-HH-9999',
'KA-01-P-333']
assert parking_lot.slot_numbers_for_cars_with_colour('White') == [1, 2, 4]
assert parking_lot.slot_number_for_registration_number('KA-01-HH-3141') == 6
assert parking_lot.slot_number_for_registration_number('MH-04-AY-1111') is None
How to run test cases:
python3.6 test.py
I also have added interactive command line utils where user can either pass a file as input or individual commands.
#process_input.py
#!/usr/bin/env python
import fileinput
import sys
from parking_lot import ParkingLot, Car
parking_lot = ParkingLot()
def process(command_params):
command_with_params = command_params.strip().split(' ')
# print(command_with_params)
command = command_with_params[0]
if command == 'create_parking_lot':
assert len(command_with_params) == 2, "create_parking_lot needs no of slots as well"
assert command_with_params[1].isdigit() is True, "param should be 'integer type'"
parking_lot.create_parking_lot(int(command_with_params[1]))
elif command == 'park':
assert len(command_with_params) == 3, "park needs registration number and color as well"
car = Car(command_with_params[1], command_with_params[2])
parking_lot.park(car)
elif command == 'leave':
assert len(command_with_params) == 2, "leave needs slot number as well"
assert command_with_params[1].isdigit() is True, "slot number should be 'integer type'"
parking_lot.leave(int(command_with_params[1]))
elif command == 'status':
parking_lot.status()
elif command == 'registration_numbers_for_cars_with_colour':
assert len(command_with_params) == 2, "registration_numbers_for_cars_with_colour needs color as well"
parking_lot.registration_numbers_for_cars_with_colour(command_with_params[1])
elif command == 'slot_numbers_for_cars_with_colour':
assert len(command_with_params) == 2, "slot_numbers_for_cars_with_colour needs color as well"
parking_lot.slot_numbers_for_cars_with_colour(command_with_params[1])
elif command == 'slot_number_for_registration_number':
assert len(command_with_params) == 2, "slot_number_for_registration_number needs registration_number as well"
parking_lot.slot_number_for_registration_number(command_with_params[1])
elif command == 'exit':
exit(0)
else:
raise Exception("Wrong command")
if len(sys.argv) == 1:
while True:
line = input()
process(line)
else:
for line in fileinput.input():
process(line)
this commands.txt:
create_parking_lot 6
park KA-01-HH-1234 White
park KA-01-HH-9999 White
park KA-01-BB-0001 Black
park KA-01-HH-7777 Red
park KA-01-HH-2701 Blue
park KA-01-HH-3141 Black
leave 4
status
park KA-01-P-333 White
park DL-12-AA-9999 White
registration_numbers_for_cars_with_colour White
slot_numbers_for_cars_with_colour White
slot_number_for_registration_number KA-01-HH-3141
slot_number_for_registration_number MH-04-AY-1111
how to run through commands.txt as input file:
python3.6 process_input.py commands.txt
output:
Created a parking lot with 6 slots
Allocated slot number: 1
Allocated slot number: 2
Allocated slot number: 3
Allocated slot number: 4
Allocated slot number: 5
Allocated slot number: 6
Slot number 4 is free
Slot No. Registration No Colour
1 KA-01-HH-1234 White
2 KA-01-HH-9999 White
3 KA-01-BB-0001 Black
5 KA-01-HH-2701 Blue
6 KA-01-HH-3141 Black
Allocated slot number: 4
Sorry, parking lot is full
KA-01-HH-1234, KA-01-HH-9999, KA-01-P-333
1, 2, 4
6
Not found
Similarly you can run individual commands as :
python3.6 process_input.py
parking_lot.park_car(car)
toparking_lot.park(car)
to be nice. \$\endgroup\$get_nearest_slot
without actually parking any car, you will run out of ALL the slots without any car being parked... \$\endgroup\$