Truncate and round all elements of a list to 8 characters

Viewed 102

I need to truncate / round / justify all the elements of a list to 8 characters. The input list can contain int (that are never too long), str (that I can truncate) and floats as float float64 or str.

Below is a sample of my code :

data = [12452, "too much characters", 0.12457544512, -0.12457544512, "-1245154.8"]
processedData = []

for d in data:
    processedValue = str(d)
    if len(processedValue) > 8 and '.' in processedValue:
        decIndex = processedValue.index(".")
        processedValue = str(round(float(processedValue), 8 - (decIndex + 1)))
    elif len(processedValue) > 8:
        processedValue = processedValue[:8]

    processedData.append(processedValue.rjust(8, " "))

print(processedData)

The output and desired output :

['   12452', 'too much', '0.124575', '-0.12458', '-1245150.0'] # Output
['   12452', 'too much', '0.124575', '-0.12458', '-1245155'] # Desired Output

When the decimal is near the end of the 8 characters, my values are not rounded at the correct index. When I replace the elif condition by if, the length is correct but the last digit is still wrong. I've tried some other changes ending up in introducing errors for the other values.

2 Answers

I would use f-strings for string formatting. As the other user already answered check for the type:

  • using isinstance() builtin function
  • a custom defined function is_float(s) that returns True if value or string can be converted to float (without exception).

Then you can left-pad to a fixed-width string of 8 characters with the format literal :8 and even round-up to an integer representation with 0 decimal places using :.0f. Or use both combined: :8.0f - all inside the curly-braces appended to the expression to format (here: d or converted float(d)):

f"{float(d):8.0f}" if isinstance(d, float) or is_float(d) else f"{d:8}"

Including a bit debug-prints at the beginning:

import math
data = [12452, "too much characters", 0.12457544512, -0.12457544512, "-1245154.8"]
print(f"input: {data}")
print(f"dt: {[type(d) for d in data]}")
def is_float(s):
    try:
        float(s)
    except ValueError:
        return False
    return True


processedData = []
for d in data:
    processedValue =  f"{float(d):8.0f}" if isinstance(d, float) or is_float(d) else f"{d:8}"
    print(processedValue)
    if len(processedValue) > 8 and '.' in processedValue:
        decIndex = processedValue.index(".")
        processedValue = str(round(float(processedValue), 8 - (decIndex + 1)))
    elif len(processedValue) > 8:
        processedValue = processedValue[:8]
    processedData.append(processedValue.rjust(8, " "))

print(f"output: {processedData}")

Prints as final line the expected:

input: [12452, 'too much characters', 0.12457544512, -0.12457544512, '-1245154.8']
dt: [<class 'int'>, <class 'str'>, <class 'float'>, <class 'float'>, <class 'str'>]
   12452
too much characters
       0
      -0
-1245155
output: ['   12452', 'too much', '       0', '      -0', '-1245155']

See also:

I guess this is one way to fix it with the current data. Results may vary depending on the input.

data = [12452, "too much characters", 0.12457544512, -0.12457544512, "-1245154.8"]
processedData = []

for entry in data:
    try:
        entry = float(entry)
    except ValueError:
        pass
    if isinstance(entry, float):
        rounded = round(entry)
        if rounded == 0:
            entry = round(entry,8-(str(entry).index(".")+1))
        else:
            entry = rounded
    entry = str(entry)[:8]
    processedData.append(entry.rjust(8, " "))

print(processedData)

Result:

['   12452', 'too much', '0.124575', '-0.12458', '-1245155']
Related