0

My code contains multiple lines of a nested for loop . I wanted to try and reduce the amount of nested for loops being called by putting the code into its own function similar to the do_for_each function below. Within the nested for loop I want to call another function. Below is a working example:

def do_for_each(self, func, h, w, init_data):
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(x, y)
        return init_data

def calculate_land_neighbours(self, x, y):
        return self.lscape[x-1,y] + self.lscape[x+1,y] + self.lscape[x,y-1] + self.lscape[x,y+1]

ouput = self.do_for_each(self.calculate_land_neighbours, self.h+1, self.w+1, data)

However, my problem arises when the function called within do_for_each does not take parameters x or y but another variable. For instance a new function would look like:

def add_to_density_array(self, seed):
        if seed == 0:
            return 0
        else:
            return random.uniform(0, 5.0)

output2 = self.do_for_each(self.add_to_density_array, self.h+1, self.w+1, data, seed)

For this to run properly I would need to amend my do_for_each function to:

def do_for_each(self, func, h, w, init_data, seed):
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(seed)
        return init_data

Would anyone have any recommendations where I could keep the modularised code of the do_for_each function but call functions within do_for_each that do not have the same input parameters?

1
  • Update: Thank you all for the useful answers. The answer from Konrad Rudolph using lambda seems to be the most relevant to my situation as other functions which use other defined variables will also be called within the do_for_each function. Commented Sep 19, 2020 at 10:53

3 Answers 3

1

Fundamentally, your two do_for_each functions are just very different. They don’t really perform the same transformation at all — one changes matrix entries as a function of the x, y indices, and another doesn’t.

I would consider using a different abstraction here.

That said, you can make this work without changing the original do_for_each: pass a lambda that wraps add_to_density_array, instead of passing the latter directly:

add_to_density = lambda x, y: self.add_to_density_array(seed)
output2 = self.do_for_each(add_to_density, self.h+1, self.w+1, data)
Sign up to request clarification or add additional context in comments.

Comments

0

You can use default parameter of seed as None and check if it exits and operate accordingly:

def do_for_each(self, func, h, w, init_data, seed=None):
    for x in range(1, h):
        for y in range(1, w):
            # If no seed provided
            if seed is None:
                init_data[x, y] = func(x, y)
            # Else, seed provided - use it
            else:
                init_data[x, y] = func(seed)
    return init_data

This has the advantage of backward compatibility with the "old" do_for_each(self, func, h, w, init_data).

Comments

0

You can try out Overloading Functions, here is a possible solution. You can read more here - https://www.geeksforgeeks.org/python-method-overloading/

def do_for_each(self, func, h, w, init_data, seed=None):
    if seed==None:
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(x, y)
        return init_data
    else:
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(seed)
        return init_data

Comments

Your Answer

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.