CodeWars: RGB To Hexadecimal

Description

Given three arguments r, g, and b which are integers from 0 to 255 representing RGB values, convert them to a six digit (zero-padded) hexadecimal string. Invalid (out of range) values need to be rounded to nearest value.

The Code

Imports

# pypi
from expects import equal, expect

Submission

HEX_DIGITS = "0123456789ABCDEF"
RGB_TO_HEX = dict(zip(range(len(HEX_DIGITS)), HEX_DIGITS))
HEX = 16

def rgb(r: int, g: int, b: int) -> str:
    """Convert RGB to Hexadecimal

    If the values are out of bounds they will be set to the nearest limit

    e.g. -1 becomes 0 and 2919 becomes 255

    Non-integers will raise an error

    Args:
     r: red channel (0-255)
     g: green channel (0-255)
     b: blue channel (0-255)

    Returns:
     6-digit hexadecimal equivalent of r, g, b
    """
    colors = (max(min(color, 255), 0) for color in (r, g, b))
    converted = ((RGB_TO_HEX[color//HEX], RGB_TO_HEX[color % HEX])
                 for color in colors)
    return "".join((y for x in converted for y in x))
expect(rgb(0,0,0)).to(equal("000000"))
expect(rgb(1,2,3)).to(equal("010203"))
expect(rgb(255,255,255)).to(equal("FFFFFF"))
expect(rgb(254,253,252)).to(equal("FEFDFC"))
expect(rgb(-20,275,125)).to(equal("00FF7D"))

Alternatives

A surprising number of people used the string formatting - {:02X} to convert the numbers to hexadecimal. I think that's sort of the problem with these earlier puzzles - there's a big question of how much of python's built in functionality you should use. I guess since I use string formatting a lot that might make sense as a shortcut in this case.

def rgb_2(r: int, g: int, b: int) -> str:
    """Convert RGB to Hexadecimal

    If the values are out of bounds they will be set to the nearest limit

    e.g. -1 becomes 0 and 2919 becomes 255

    Non-integers will raise an error

    Args:
     r: red channel (0-255)
     g: green channel (0-255)
     b: blue channel (0-255)

    Returns:
     6-digit hexadecimal equivalent of r, g, b
    """
    return "".join((f"{max(min(color, 255), 0):02X}" for color in (r, g, b)))
expect(rgb_2(0,0,0)).to(equal("000000"))
expect(rgb_2(1,2,3)).to(equal("010203"))
expect(rgb_2(255,255,255)).to(equal("FFFFFF"))
expect(rgb_2(254,253,252)).to(equal("FEFDFC"))
expect(rgb_2(-20,275,125)).to(equal("00FF7D"))

Not quite so readable, but short.