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 ?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Feb 27, 2018 at 16:55
\$\endgroup\$

3 Answers 3

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)
answered Feb 27, 2018 at 17:03
\$\endgroup\$
2
  • \$\begingroup\$ This is perfect. I didn't think of format! This is so simple and yet so beautiful :) Thanks! \$\endgroup\$ Commented Feb 27, 2018 at 17:10
  • 2
    \$\begingroup\$ float is definitely the least hacks solution. Also consider Decimal. \$\endgroup\$ Commented Feb 27, 2018 at 17:11
1
\$\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.

answered Feb 27, 2018 at 17:01
\$\endgroup\$
1
\$\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()))
answered Feb 27, 2018 at 17:01
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Unfortunately this won't work as you'll get: ValueError :) \$\endgroup\$ Commented Feb 27, 2018 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\$ Commented Feb 27, 2018 at 17:07
  • \$\begingroup\$ Well, float will do, will amend :) \$\endgroup\$ Commented Feb 27, 2018 at 17:12

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.