Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
.venv
137 changes: 137 additions & 0 deletions laptop_allocation/laptop_allocation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from dataclasses import dataclass
from enum import Enum
from typing import List
from typing import Dict

# ============================================================================
# ENUM DEFINITIONS
# ============================================================================
class OperatingSystem(Enum):
MACOS = "macOS"
ARCH = "Arch Linux"
UBUNTU = "Ubuntu"

# ============================================================================
# DATA CLASSES
# ============================================================================
@dataclass(frozen=True)
class Person:
name: str
age: int
# Sorted in order of preference, most preferred is first.
preferred_operating_system: tuple

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a tuple rather than a list?



@dataclass(frozen=True)
class Laptop:
id: int
manufacturer: str
model: str
screen_size_in_inches: float
operating_system: OperatingSystem

# ============================================================================
# HELPER FUNCTION
# ============================================================================
"""
Calculates how "sad" a person would be with a given laptop allocation.

Sadness is defined as the position (0-indexed) of the laptop's OS
in the person's preference list. For example:
- If preferences are [UBUNTU, ARCH, MACOS] and they get UBUNTU: sadness = 0
- If preferences are [UBUNTU, ARCH, MACOS] and they get ARCH: sadness = 1
- If preferences are [UBUNTU, ARCH, MACOS] and they get MACOS: sadness = 2
- If they get an OS not in their preferences: sadness = 100

Args:
person: The person receiving the laptop
laptop: The laptop being allocated

Returns:
An integer representing sadness (0 = most happy, 100 = not in preferences)
"""

def calculate_sadness(person:Person, laptop:Laptop)-> int:
if laptop.operating_system in person.preferred_operating_system:
# Find the index (position) of this OS in their preference list
sadness = person.preferred_operating_system.index(laptop.operating_system)
return sadness
else:
# OS not in preferences = very sad
return 100

# ============================================================================
# TEST DATA
# ============================================================================

laptops = [
Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13,
operating_system=OperatingSystem.ARCH),
Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15,
operating_system=OperatingSystem.UBUNTU),
Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15,
operating_system=OperatingSystem.UBUNTU),
Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13,
operating_system=OperatingSystem.MACOS),
Laptop(id=5, manufacturer="Apple", model="macBook Pro", screen_size_in_inches=16,
operating_system=OperatingSystem.MACOS),
Laptop(id=6, manufacturer="Lenovo", model="ThinkPad", screen_size_in_inches=14,
operating_system=OperatingSystem.UBUNTU),
Laptop(id=7, manufacturer="System76", model="Lemur Pro", screen_size_in_inches=15,
operating_system=OperatingSystem.ARCH),
Laptop(id=8, manufacturer="Framework", model="Framework 13", screen_size_in_inches=13,
operating_system=OperatingSystem.UBUNTU),
]

people = [
Person(name="Imran", age=22, preferred_operating_system=(OperatingSystem.UBUNTU, OperatingSystem.MACOS)),
Person(name="Eliza", age=34, preferred_operating_system=(OperatingSystem.ARCH, OperatingSystem.UBUNTU)),
Person(name="Marcus", age=28, preferred_operating_system=(OperatingSystem.MACOS, OperatingSystem.UBUNTU)),
Person(name="Sofia", age=31, preferred_operating_system=(OperatingSystem.UBUNTU,)),
Person(name="James", age=25, preferred_operating_system=(OperatingSystem.ARCH, OperatingSystem.MACOS)),
Person(name="Nina", age=29, preferred_operating_system=(OperatingSystem.MACOS, OperatingSystem.ARCH, OperatingSystem.UBUNTU)),
]



# ============================================================================
# TESTING
# ============================================================================

def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person,Laptop]:

if len(laptops) < len(people):
raise ValueError("Not enough laptops to allocate one per person")


people_sorted = sorted(people, key = lambda p: len(p.preferred_operating_system))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch - haven't seen anyone else do this, but it is a clever tweak to the algorithm


result={}
available_laptops = laptops.copy()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot that you need the copy if you don't want to change the original


for person in people_sorted:
smallest_sadness = float("inf")
best_laptop = None

for laptop in available_laptops:
sadness = calculate_sadness(person, laptop)
if sadness < smallest_sadness:
smallest_sadness = sadness
best_laptop = laptop

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could of course break out of the loop if sadness is 0


result[person]= best_laptop
available_laptops.remove(best_laptop)

return result

allocate_laptops(people, laptops)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this first call to allocate laptops here?

allocation = allocate_laptops(people, laptops)

print("\n" + "="*50)
print("FINAL ALLOCATION:")
print("="*50)
for person, laptop in allocation.items():
print(f"{person.name}: {laptop.manufacturer} {laptop.model} ({laptop.operating_system.value})")