Last active
May 22, 2022 12:05
-
-
Save erikseulean/913aa9ada62296c75f20037ef4584b9b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from collections import defaultdict | |
| class ConversionNotPossible(Exception): | |
| def __init__(self, from_unit, to_unit): | |
| super(Exception).__init__() | |
| self.from_unit = from_unit | |
| self.to_unit = to_unit | |
| def __repr__(self) -> str: | |
| return f"Cannot convert from {self.from_unit} to {self.to_unit}" | |
| class UnitConversion: | |
| def __init__(self): | |
| self._conversions = defaultdict(dict) | |
| def store_conversion_units(self, conversion_pairs): | |
| for from_unit, conversion_factor, to_unit in conversion_pairs: | |
| self._conversions[from_unit][to_unit] = conversion_factor | |
| self._conversions[to_unit][from_unit] = 1/conversion_factor | |
| def convert(self, value, from_unit, to_unit): | |
| # this makes the first call for a from-to pair take the performance hit of the | |
| # graph traversal, however, we can eagerly store all the conversion units | |
| # when we construct the graph. That way the convert function would be O(1) | |
| conversion_factor = self.find_conversion_factor(from_unit, to_unit) | |
| return value * conversion_factor | |
| def find_conversion_factor(self, from_unit, to_unit): | |
| visited_units = set() | |
| def _find_conversion_factor(from_unit, to_unit): | |
| if from_unit in visited_units: | |
| return | |
| if from_unit not in self._conversions: | |
| return | |
| if to_unit in self._conversions[from_unit]: | |
| return self._conversion[from_unit][to_unit] | |
| for unit, conversion_factor in self._conversions[from_unit].items(): | |
| overall_conversion_factor = self.find_conversion_factor(self, unit, to_unit) | |
| if not overall_conversion_factor: | |
| continue | |
| return overall_conversion_factor * conversion_factor | |
| visited_units.add(from_unit) | |
| conversion_factor = _find_conversion_factor(from_unit, to_unit) | |
| if not conversion_factor: | |
| raise ConversionNotPossible(from_unit, to_unit) | |
| self._conversions[from_unit][to_unit] = conversion_factor | |
| self._conversions[to_unit][from_unit] = 1/conversion_factor | |
| return conversion_factor |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment