diff --git a/implement-laptop-allocation/README.md b/implement-laptop-allocation/README.md new file mode 100644 index 00000000..ce85692d --- /dev/null +++ b/implement-laptop-allocation/README.md @@ -0,0 +1,42 @@ +In the prep, there was an exercise around finding possible laptops for a group of people. + +Your exercise is to extend this to actually allocate laptops to the people. + +Given these class definitions: + +from dataclasses import dataclass +from enum import Enum +from typing import List + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + # Sorted in order of preference, most preferred is first. + preferred_operating_system: List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem +Write a function with this signature: + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]: +Every person should be allocated exactly one laptop. + +If we define "sadness" as the number of places down in someone's ranking the operating system the ended up with (i.e. if your preferences were [UBUNTU, ARCH, MACOS] and you were allocated a MACOS machine your sadness would be 2), we want to minimise the total sadness of all people. If we allocate someone a laptop with an operating system not in their preferred list, treat them as having a sadness of 100. + +Maximum time in hours +3 + +How to submit +Submit a PR to this repo containing your function (and any supporting code). diff --git a/implement-laptop-allocation/main.py b/implement-laptop-allocation/main.py new file mode 100644 index 00000000..380ea2c5 --- /dev/null +++ b/implement-laptop-allocation/main.py @@ -0,0 +1,113 @@ +from dataclasses import dataclass +from enum import Enum +from typing import List, Dict + +from scipy.optimize import linear_sum_assignment + + + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + # Sorted in order of preference, most preferred is first. + preferred_operating_systems: List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem + + +def sadness(person: Person, laptop: Laptop) ->int: + if laptop.operating_system in person.preferred_operating_systems: + return person.preferred_operating_systems.index(laptop.operating_system) + return 100 + + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]: + + if len(people) != len(laptops): + raise ValueError("Number of individuals and laptops must be equal") + + cost_matrix = [ + [sadness(person, laptop) for laptop in laptops] + for person in people + ] + + person_indices, laptop_indices = linear_sum_assignment(cost_matrix) + + return {people[p_idx]: laptops[l_idx] + for p_idx, l_idx in zip(person_indices, laptop_indices) + + } + + + + + +if __name__ == "__main__": + people = [ + Person( + name="Alice", + age=30, + preferred_operating_systems=[ + OperatingSystem.MACOS, + OperatingSystem.UBUNTU, + ], + ), + Person( + name="Bob", + age=25, + preferred_operating_systems=[ + OperatingSystem.UBUNTU, + OperatingSystem.MACOS, + ], + ), + Person( + name="Carol", + age=28, + preferred_operating_systems=[ + OperatingSystem.ARCH, + OperatingSystem.MACOS, + ], + ), + ] + + laptops = [ + Laptop( + id=1, + manufacturer="Apple", + model="MacBook Air", + screen_size_in_inches=13.3, + operating_system=OperatingSystem.MACOS, + ), + Laptop( + id=2, + manufacturer="Dell", + model="XPS", + screen_size_in_inches=13.0, + operating_system=OperatingSystem.UBUNTU, + ), + Laptop( + id=3, + manufacturer="Lenovo", + model="ThinkPad", + screen_size_in_inches=14.0, + operating_system=OperatingSystem.ARCH, + ), + ] + + allocation = allocate_laptops(people, laptops) + + for person, laptop in allocation.items(): + print(f"{person.name} → {laptop.model} ({laptop.operating_system.value})")