4
\$\begingroup\$

I've wrote this code and it does what is expected. However, I'm thinking if there are better ways to write this, specially if is useful to wrap it in a class, or other ways to make it less loosen. I'll be glad and grateful for any others corrections or suggestions.

interest_list = [0.5,  0.4,  0.3,  0.5,  0.7, 0.4,  -0.2,  -0.5,  0.3,
            0.7,  0.9,  1.0]

def get_unitary(interest_list): unit_list = [] for i in range(len(interest_list)): unit_list.append(1+ interest_list[i]/100) return unit_list # I've tested on some lists and found this faster than using reduce() def prod(uni_list): p = 1 for i in uni_list: p *= i return p def get_accrued(prod): sub_1 = prod -1 return sub_1 * 100 accrued = get_accrued(prod(get_unitary(interest_list)))
\$\endgroup\$
2
\$\begingroup\$

It'd be easier to help if you explained the purpose of the algorithm.

However the obvious simplification is in the get_unitary function. You don't want that list, you only want to work with the values that come back from that operation. So you can omit the creation and population of the list and make a generator function that just pops out the values sequentially using yield

def get_unitary(interest_list):
    for value in interest_list:
        yield (1 + value / 100)

Since prod just iterates the result, this produces the same output.

In fact, the function itself is so simple that you can reduce it even further by turning the get_unitary function into a generator expression. This is a different way of writing the version above.

def get_unitary(interest_list):
    return (1 + value / 100  for value in interest_list)

But since that function is not actually consumed by any other code, you can just include it in the prod() function:

def product(interest_list):
    unitary_generator = ( (1 + value / 100) for value in interest_list)
    p = 1
    for i in unitary_generator:
        p *= i
    return p

accrued = get_accrued(product(interest_list))

(I changed prod to product for clarity).

Without knowing the context, its hard to know if it makes sense to keep the get_accrued function on its own. Since it only consumes the result of product() you can fold them together, maybe including a comment about the algorithm. So that will get you to this as a final form:

interest_list = [0.5, 0.4, 0.3, 0.5, 0.7, 0.4, -0.2, -0.5, 0.3,
                 0.7, 0.9, 1.0]


def accrued_interest(interest_list):
    unitary_generator = ( (1 + value / 100) for value in interest_list)
    p = 1
    for i in unitary_generator:
        p *= i

    # if the logic behind this is not clear,
    # an comment here would be useful!
    return  (p - 1) * 100


accrued = accrued_interest(interest_list)

And of course you could also omit the generator altogether if your input data were just preformatted into numbers into the right range, such as [150, 140, 130... ] and so on

\$\endgroup\$
1
  • \$\begingroup\$ Hello theodox, I think that my meager english doesn't help me explaining myself, maybe accrued isn't the right term. But I want to use this so I don't need to check the correction percentage of the inflation of brazil, without resorting to the citizens calculator bit.ly/1o4zwHS On the last two pages of this faq bit.ly/2P1pY4P there are the methods for getting the index, the - 1 part of my code is to get the corresponding percentage. And thank you exceptionally for showing the uses of generators and the resources on them. \$\endgroup\$ – Celso Pereira Neto Aug 11 '18 at 3:10
4
\$\begingroup\$

You can make it pretty short in Python 3 if you use functools.reduce():

from functools import reduce

interest_list = [0.5, 0.4, 0.3, 0.5, 0.7, 0.4, -0.2, -0.5, 0.3, 0.7, 0.9, 1.0]

l = [1 + n / 100 for n in interest_list]

accrued = (reduce(lambda x, y: x * y, l) - 1) * 100

In Python 2.7 no imports are needed.

\$\endgroup\$

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.