1

I'm programming a math exam package that contains a module, root.py (and polynomial.py), which effectively represents a 1st order polynomial, or binomial. I would like to format the class Root: object I've created to be visualized in its most reduced (human-readable) form. For example, if the root is of the form: ax + b; where a and b represent coefficients of the root, the '+/-' should only exist if b != 0, and the a term should omit the '+' sign if > 1, and omit the value 1 from the leading coefficient.

I've looked at this documentation, as well as this stack overflow article

Here's some relevant code:

root.py

class Root:
    def __init__(self, a=0, b=0):
        # Does stuff with a/b to get coefficients

    def __str__(self):
        a, b = '', '0'
        ### Begin code block of concern
        if self.a:
            b = ''
            if self.a == 1:
                a = 'x'
            elif self.a == -1:
                a = '-x'
            else:
                a = '{:-d}x'.format(self.a)
        ### End code block of concern
        if self.b:
            b = '{:+d}'.format(self.b)
        return a + b # The string '{-}ax{+/-}b'

Examples:

  • -3x+7, 3x-7 NOT +3x-7
  • 7-3x, -7+3x NOT +7-3x
  • -x-1, x+2 NOT -1x-1, +1x+2, or 1x+2

The above mentioned code already (sort-of) works, however verbose. Full disclosure, I'm only expecting a more 'pythonic' way to do this. It would be nice but unnecessary to have the string format allow for the form b+ax as opposed to only ax+b, but this question is out of scope.

jsonV
  • 1,650
  • 2
  • 9
  • 23
  • Have you already take a look at sympy? http://scipy-lectures.org/advanced/sympy.html#simplify – olinox14 May 13 '19 at 12:56
  • "_I'm only expecting a more 'pythonic' way to do this._" Unless you're looking for a [potentially obfuscated] one-liner to replace those 6 lines of concern, personally I would prefer the code in the question, as it's more readable, however verbose. – TrebledJ May 13 '19 at 12:56
  • @TrebledJ That's not to say I would prefer a confusing one-liner. It's more so that I would like some magical operation that handles the logic for me already (e.g. potentially sympy's simplify -- although not built-in). The str.format() method for instance was particularly helpful in removing the '+' sign for `a`, but not for `b` with `{:+-d}`. My `+`/`-` logic beforehand was horrendously verbose... – jsonV May 13 '19 at 12:58
  • Note you are not considering the case where both `a` and `b` are zero (presumably the resulting string should be `'0'` and not an empty string). – jdehesa May 13 '19 at 13:03
  • Also a number of related / possible duplicates: [Pretty polynomial printing in python](https://stackoverflow.com/q/20749463), [Printing a polynomial in python](https://stackoverflow.com/q/34843514), [Print polynomial in variable format in python](https://stackoverflow.com/q/33304178), [Pretty printing polynomials with dictionary python](https://stackoverflow.com/q/29473533), [String representation of a polynomial (CR SE)](https://codereview.stackexchange.com/q/54646). – jdehesa May 13 '19 at 13:08
  • @jdehesa Thanks for bringing the edge case to my eyes. When `a` and `b` are both zero (e.g. rt = Root(), printing rt doesn't print an empty string. The else condition assigns `a = '0x'` which I agree isn't the most human readable. Will handle in an edit soon. – jsonV May 13 '19 at 13:21

2 Answers2

1

As said in the comment, you could simplify your code by using the scypy library, what could lead you to something like that:

from sympy.core.symbol import Symbol
from sympy.simplify import simplify

x = Symbol('x')
print(simplify(-1 * (-3 * x + 7)))
# >>> output: 3*x - 7

Or, in your case:

a, b = 3, 2
print(simplify(a * x + b)) # >>> 3*x + 2

a, b = -1, 2
print(simplify(a * x + b)) # >>> 2 - x

a, b = 0, -2
print(simplify(a * x + b)) # >>> -2    
olinox14
  • 6,177
  • 2
  • 22
  • 39
1

If you don't want to add another dependency, you can try something like:

lookup = { 1: 'x', -1: '-x'}
a = lookup.get(a, '{:-d}x'.format(a))
ChatterOne
  • 3,381
  • 1
  • 18
  • 24
  • I think more something like `({0: '', -1: '-x', 1: 'x'}.get(self.a, f'{self.a}x') + (f'{self.b:+d}' if self.b else '')) or '0'`. – jdehesa May 13 '19 at 13:12
  • 2
    @jdehesa That would make it complete but also IMO very unreadable, I'd rather have two separate lines – ChatterOne May 13 '19 at 13:13
  • Although the short answer to my question is no, Python3 doesn't directly support this innately with its format method or other built-ins... I'm accepting this dictionary lookup based answer as it answers the question using Python3 built-ins. – jsonV May 13 '19 at 14:02