Skip to content

Commit a7e4b23

Browse files
manueldilullopoyea
andauthored
Add prefix conversions for strings (TheAlgorithms#5453)
* First commit for add_prefix_conversion * Class names in CamelCase, str.format() to f-string * Fixed following pre-commit guidelines * solved issues with mypy and enum.Enum * Rename add_prefix_conversion.py to prefix_conversions_string.py Co-authored-by: John Law <[email protected]>
1 parent 10d0e4e commit a7e4b23

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
"""
2+
* Author: Manuel Di Lullo (https://github.com/manueldilullo)
3+
* Description: Convert a number to use the correct SI or Binary unit prefix.
4+
5+
Inspired by prefix_conversion.py file in this repository by lance-pyles
6+
7+
URL: https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes
8+
URL: https://en.wikipedia.org/wiki/Binary_prefix
9+
"""
10+
11+
from __future__ import annotations
12+
13+
from enum import Enum, unique
14+
from typing import Type, TypeVar
15+
16+
# Create a generic variable that can be 'Enum', or any subclass.
17+
T = TypeVar("T", bound="Enum")
18+
19+
20+
@unique
21+
class BinaryUnit(Enum):
22+
yotta = 80
23+
zetta = 70
24+
exa = 60
25+
peta = 50
26+
tera = 40
27+
giga = 30
28+
mega = 20
29+
kilo = 10
30+
31+
32+
@unique
33+
class SIUnit(Enum):
34+
yotta = 24
35+
zetta = 21
36+
exa = 18
37+
peta = 15
38+
tera = 12
39+
giga = 9
40+
mega = 6
41+
kilo = 3
42+
hecto = 2
43+
deca = 1
44+
deci = -1
45+
centi = -2
46+
milli = -3
47+
micro = -6
48+
nano = -9
49+
pico = -12
50+
femto = -15
51+
atto = -18
52+
zepto = -21
53+
yocto = -24
54+
55+
@classmethod
56+
def get_positive(cls: Type[T]) -> dict:
57+
"""
58+
Returns a dictionary with only the elements of this enum
59+
that has a positive value
60+
>>> from itertools import islice
61+
>>> positive = SIUnit.get_positive()
62+
>>> inc = iter(positive.items())
63+
>>> dict(islice(inc, len(positive) // 2))
64+
{'yotta': 24, 'zetta': 21, 'exa': 18, 'peta': 15, 'tera': 12}
65+
>>> dict(inc)
66+
{'giga': 9, 'mega': 6, 'kilo': 3, 'hecto': 2, 'deca': 1}
67+
"""
68+
return {unit.name: unit.value for unit in cls if unit.value > 0}
69+
70+
@classmethod
71+
def get_negative(cls: Type[T]) -> dict:
72+
"""
73+
Returns a dictionary with only the elements of this enum
74+
that has a negative value
75+
@example
76+
>>> from itertools import islice
77+
>>> negative = SIUnit.get_negative()
78+
>>> inc = iter(negative.items())
79+
>>> dict(islice(inc, len(negative) // 2))
80+
{'deci': -1, 'centi': -2, 'milli': -3, 'micro': -6, 'nano': -9}
81+
>>> dict(inc)
82+
{'pico': -12, 'femto': -15, 'atto': -18, 'zepto': -21, 'yocto': -24}
83+
"""
84+
return {unit.name: unit.value for unit in cls if unit.value < 0}
85+
86+
87+
def add_si_prefix(value: float) -> str:
88+
"""
89+
Function that converts a number to his version with SI prefix
90+
@input value (an integer)
91+
@example:
92+
>>> add_si_prefix(10000)
93+
'10.0 kilo'
94+
"""
95+
prefixes = SIUnit.get_positive() if value > 0 else SIUnit.get_negative()
96+
for name_prefix, value_prefix in prefixes.items():
97+
numerical_part = value / (10 ** value_prefix)
98+
if numerical_part > 1:
99+
return f"{str(numerical_part)} {name_prefix}"
100+
return str(value)
101+
102+
103+
def add_binary_prefix(value: float) -> str:
104+
"""
105+
Function that converts a number to his version with Binary prefix
106+
@input value (an integer)
107+
@example:
108+
>>> add_binary_prefix(65536)
109+
'64.0 kilo'
110+
"""
111+
for prefix in BinaryUnit:
112+
numerical_part = value / (2 ** prefix.value)
113+
if numerical_part > 1:
114+
return f"{str(numerical_part)} {prefix.name}"
115+
return str(value)
116+
117+
118+
if __name__ == "__main__":
119+
import doctest
120+
121+
doctest.testmod()

0 commit comments

Comments
 (0)