4
\$\begingroup\$

Background

I have a list of strings containing numbers. Each string is 8 characters long. For example :

'-123.456'
' -12.345'
'  -1.234'
' 123.456'
'  12.345'
'   1.234'

The longest number possible is ' 999.999' ; the smallest number is ' 0.000' and there always are 3 numbers in the decimal.

What I want to do is compute the opposite of each number, and return it as a string of length 8, with the opposite sign next to the number.

For example :

'-123.456' should yield ' 123.456'
' -12.345' should yield '  12.345'
'  -1.234' should yield '   1.234'
' 123.456' should yield '-123.456'
'  12.345' should yield ' -12.345'
'   1.234' should yield '  -1.234'

What I did

I wrote the following code, which works :

def opposite(x):
    if x.startswith('  -'):
        xopp = '   ' + x[3:]
    elif x.startswith(' -'):
        xopp = '  ' + x[2:]
    elif x.startswith('-'):
        xopp = ' ' + x[1:]
    elif x.startswith('   '):
        xopp = '  -' + x[3:]
    elif x.startswith('  '):
        xopp = ' -' + x[2:]
    elif x.startswith(' '):
        xopp = '-' + x[1:]
    return xopp

My question

I feel like this code is completely "unpythonic" and could be replaced by a one-liner. So the question is: does anyone have an idea to make it more pythonic or even a one-liner ?

\$\endgroup\$
5
\$\begingroup\$

There are only really two things you need here.

  • float. Which allows you to convert the input to a floating point number. If you change to needing more precision or larger numbers, decimal would be a better choice - thanks @200_success. And,
  • str.format. Which uses the Format String Syntax. Which you can use pad the left with spaces, so the output has a width of eight. {: >8}. This however needs to be adjusted for your "there always are 3 numbers in the decimal" requirement, and so you can force this too with {: >8.3f}.

And so I'd use:

def opposite(x):
    return '{: >8.3f}'.format(-float(x))

If however you don't want to use float then you can use str.lstrip. With just one if-else:

def opposite(x):
    x = x.lstrip()
    if x.startswith('-'):
        x = x[1:]
    else:
        x = '-' + x
    return '{: >8}'.format(x)
\$\endgroup\$
  • \$\begingroup\$ This is perfect. I didn't think of format! This is so simple and yet so beautiful :) Thanks! \$\endgroup\$ – Deuce Feb 27 '18 at 17:10
  • 2
    \$\begingroup\$ float is definitely the least hacks solution. Also consider Decimal. \$\endgroup\$ – 200_success Feb 27 '18 at 17:11
0
\$\begingroup\$

I usually hang around python 3.x but I don't think there is any way to make it a one-liner due if you put in an "if" statement, you cannot put in another "if" statement due to which "if" statement is the next line talking about.

But as for a more efficient way, possible definitely.

\$\endgroup\$
0
\$\begingroup\$

There is definitely a way to make it a one liner, which I will post, nevertheless would be interesting to understand what's happening and how to do it

One liner

return str(-1 * float(x.strip()))

But what's happening?

First, the number you receive contains leading whitespaces, which you want to discard. For that we use the strip function, to get rid of them

x.strip()  # For an input of '  -35' will return '-35'

Now, we want to convert the number to float, cause is easier and more verbose to calculate the negative value this way. So we cast to float

float(x.strip())

Then we multiply by -1 to get the opposite

-1 * float(x.strip())

Finally we just need to cast the result to string again, because your function should return a string as you specified

str(-1 * float(x.strip()))
\$\endgroup\$
  • 1
    \$\begingroup\$ Unfortunately this won't work as you'll get: ValueError :) \$\endgroup\$ – Grajdeanu Alex. Feb 27 '18 at 17:06
  • 1
    \$\begingroup\$ Sorry but this doesn't answer my question : 1. The whole point is to keep the leading spaces to have an 8-characters long string ; 2. Casting to int() won't work, need to use float(). I will update my question to make sure it is understandable that I need to add leading spaces if my string isn't long enough. \$\endgroup\$ – Deuce Feb 27 '18 at 17:07
  • \$\begingroup\$ Well, float will do, will amend :) \$\endgroup\$ – A. Romeu Feb 27 '18 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.