简体   繁体   中英

Most pythonic way to split this line?

I am trying to reclassify an array that has values from 0 to 15 with new values from 0 to 5.

My conditions are the following:

con1 = np.in1d(arr, [0, 11, 13, 15]).reshape((y, x))  # new val 0
con2 = np.in1d(arr, [1, 2, 3, 4, 5]).reshape((y, x))  # new val 1
con3 = (arr == 6) | (arr == 7)                        # new val 2
con4 = (arr == 8) | (arr == 9)                        # new val 3
con5 = (arr == 10)                                    # new val 4
con6 = (arr == 12) | (arr == 14)                      # new val 5

I have the following line in python

return np.where(con1, 0, np.where(con2, 1, np.where(con3, 2, np.where(con4, 3, np.where(con5, 4, np.where(con6, 5, arr))))))

which is 128 characters long (including the indentation inside the function). PEP8 suggests that lines should not be over 79 characters. However I'm not sure what is the best way to split this line into multiple lines while keeping readability.

I have tried a two options but they seem hard to read.

Option 1:

return np.where(con1, 0, np.where(
    con2, 1, np.where(
        con3, 2, np.where(
            con4, 3, np.where(
                con5, 4, np.where(
                    con6, 5, arr))))))

Option 2:

return np.where(con1, 0, 
                np.where(con2, 1, 
                         np.where(con3, 2, 
                                  np.where(con4, 3, 
                                           np.where(con5, 4, 
                                                    np.where(con6, 5, arr)
                                                    )))))

You could do them all seperately. This is more readable as you can follow step by step.

filtered_result = np.where(con6, 5, arr)
filtered_result = np.where(con5, 4, filtered_result)
filtered_result = np.where(con4, 3, filtered_result)
filtered_result = np.where(con3, 2, filtered_result)
filtered_result = np.where(con2, 1, filtered_result)
filtered_result = np.where(con1, 0, filtered_result)

return filtered_result

To stick with pep8, which is what you're asking, then this is the way to go

Edit

A for loop would also significantly reduce the repetitiveness and still be readable.

connections = iter((con6, con5, con4, con3, co2, con1, con0))
filters = range(len(connections)-2, 0 -1)

filtered_result = np.where(next(connections), next(filters), arr)

for n, con, in zip(filters, connections):
    filtered_result = np.where(con, n, filtered_result)

return filtered_result

Might not be much more readable but you could try reduce :

from functools import reduce

def some_func():

    ... some code maybe ...

    args = [con1, con2, con3, con4, con5, con6]
    return reduce(
            lambda prev_arg, new_arg: np.where(*new_arg, prev_arg), 
            enumerate(args[:-1]), 
            np.where(args[-1], len(args)-1, arr)
        )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM