-1

I want to convert a dictionary into a list of strings. Although my actual code is much longer, a MWE is:

>>> import json
>>> mydict = {'c1': (84/255, 0/255, 0/255), 'c2': (15/255, 123/255, 175/255)}
>>> json.dumps(mydict)

The output is:

'{"c1": [0.32941176470588235, 0.0, 0.0], "c2": [0.058823529411764705, 0.4823529411764706, 0.6862745098039216]}'

If I try the fractions package, it seems I can convert fractions themselves into something suitable but it doesn't work for dictionaries or arrays:

from fractions import Fraction

x = Fraction(84/255).limit_denominator()
print(x)

y = Fraction(np.array([84/255, 0/255])).limit_denominator()
print(y)

z = Fraction(mydict).limit_denominator()
print(z)

I want to extract all the numerical values (while keeping them as fractions) and put them in a list, something like:

mylist = ['(84/255, 0/255, 0/255)', '(15/255, 123/255, 175/255)']

FYI I can't save the tuples as strings in my actual code (not this MWE) because I'm not allowed to change the particular format. So it's necessary to convert mydict directly, eg. like str(Fraction({'c1': (84/255, 0/255, 0/255), 'c2': (15/255, 123/255, 175/255)}).limit_denominator().

Medulla Oblongata
  • 3,771
  • 8
  • 36
  • 75
  • Then you need to store them as tuple of strings when saving to the dictionary. – PM 77-1 Jun 02 '21 at 00:05
  • 1
    Try this one https://stackoverflow.com/questions/23344185/how-to-convert-a-decimal-number-into-fraction – DevScheffer Jun 02 '21 at 00:05
  • @DevScheffer converting 0 to a specific fraction is kind of hard. (Also I suspect OP is actually looking into 1/255 based on the sample, close to single byte float... which indeed makes converting 0 to 0/255 obvious) – Alexei Levenkov Jun 02 '21 at 00:08
  • Even in your updated question, you still don't seem to comprehend that once an expression such as `84/255` is evaluated and turned into a single numeric value, an information loss has occurred (i.e. the values of the numerator and denominator used in the expression). At best all you can get is two numbers that will evaluate (approximately in many cases) to the same value. In other words, you can't do what you want. – martineau Jun 02 '21 at 00:28

3 Answers3

1

You can't: as soon as you hit "return" on the line that defines mydict, the Python interpreter evaluates all of the expressions, and you've lost the original form. There is no way you can tell 0/255 from 0/3, or 1/2 from 3/6. If you want to retain the numerator and denominator, then I suggest you use the Fraction package.

Prune
  • 76,765
  • 14
  • 60
  • 81
0

If so, why don't you store those expressions as string, and use eval whenever required:

mydict = {'c1': '(84/255, 0/255, 0/255)', 'c2': '(15/255, 123/255, 175/255)'}

evaluated = {key: eval(val) for key,val in mydict.items()}
ThePyGuy
  • 17,779
  • 5
  • 18
  • 45
0

If you know that all your fractions have a denominator of 255. You can build a helper method that will iterate through your dictionary building up its own string to display.

Here is an example:

def dump_by_fraction(dictionary: dict):
    output_string = ''
    first_item = True
    for key, faction_list in dictionary.items():
        item_output = ''
        for index, fraction in enumerate(faction_list):
            item_output += (", " if index > 0 else "") + f"{math.floor(fraction * 255)} / 255"
        output_string += ("" if first_item > 0 else ", ") + f"'{key}': [{item_output}]"
        first_item = False
    print('{' + output_string + '}')

you can try calling dump_by_fraction(mydict) instead of json.dumps(mydict)

I would use this for debugging / display purposes only because there can be data loss when converting back and forth between integers and floats.

A simpler solution could be to store the RGB values just as integer and drop the / 255 completely as you will know it's out of 255.

For Example:

mydict = {'c1': (84, 0, 0), 'c2': (15, 123, 175)}

this way to you eliminate the need to convert completly.

user1239299
  • 665
  • 8
  • 26