How to apply multiprocessing in python3.x for the following nested loop - python-3.x

for i in range(1,row):
for j in range(1,col):
if i > j and i != j:
x = Aglo[0][i][0]
y = Aglo[j][0][0]
Aglo[j][i] = offset.myfun(x,y)
Aglo[i][j] = Aglo[j][i]
Aglo[][] is a 2D array, which consists of lists in the first row
offset.myfun() is a function defined elsewhere
This might be a trivial question but i couldn't understand how to use multiprocessing for these nested loops as x,y (used in myfun()) is different for each process(if multiprocessing is used)
Thank you

If I'm reading your code right, you are not overwriting any previously calculated values. If that's true, then you can use multiprocessing. If not, then you can't guarantee that the results from multiprocessing will be in the correct order.
To use something like multiprocessing.Pool, you would need to gather all valid (x, y) pairs to pass to offset.myfun(). Something like this might work (untested):
pairs = [(i, j, Aglo[0][i][0], Aglo[j][0][0]) for i in range(1, row) for j in range(1, col) if i > j and i != j]
# offset.myfun now needs to take a tuple instead of x, y
# it additionally needs to emit i and j in addition to the return value
# e.g. (i, j, result)
p = Pool(4)
results = p.map(offset.myfun, pairs)
# fill in Aglo with the results
for pair in pairs:
i, j, value = pair
Aglo[i][j] = value
Aglo[j][i] = value
You will need to pass in i and j to offset.myfun because otherwise there is no way to know which result goes where. offset.myfun should then return i and j along with the result so you can fill in Aglo appropriately. Hope this helps.

Related

Conditionally use parts of a nested for loop

I've searched for this answer extensively, but can't seem to find an answer. Therefore, for the first time, I am posting a question here.
I have a function that uses many parameters to perform a calculation. Based on user input, I want to iterate through possible values for some (or all) of the parameters. If I wanted to iterate through all of the parameters, I might do something like this:
for i in range(low1,high1):
for j in range(low2,high2):
for k in range(low3,high3):
for m in range(low4,high4):
doFunction(i, j, k, m)
If I only wanted to iterate the 1st and 4th parameter, I might do this:
for i in range(low1,high1):
for m in range(low4,high4):
doFunction(i, user_input_j, user_input_k, m)
My actual code has almost 15 nested for-loops with 15 different parameters - each of which could be iterable (or not). So, it isn't scalable for me to use what I have and code a unique block of for-loops for each combination of a parameter being iterable or not. If I did that, I'd have 2^15 different blocks of code.
I could do something like this:
if use_static_j == True:
low2 = -999
high2 = -1000
for i in range(low1,high1):
for j in range(low2,high2):
for k in range(low3,high3):
for m in range(low4,high4):
j1 = j if use_static_j==False else user_input_j
doFunction(i, j1, k, m)
I'd just like to know if there is a better way. Perhaps using filter(), map(), or list comprehension... (which I don't have a clear enough understanding of yet)
As suggested in the comments, you could build an array of the parameters and then call the function with each of the values in the array. The easiest way to build the array is using recursion over a list defining the ranges for each parameter. In this code I've assumed a list of tuples consisting of start, stop and scale parameters (so for example the third element in the list produces [3, 2.8, 2.6, 2.4, 2.2]). To use a static value you would use a tuple (static, static+1, 1).
def build_param_array(ranges):
r = ranges[0]
if len(ranges) == 1:
return [[p * r[2]] for p in range(r[0], r[1], -1 if r[1] < r[0] else 1)]
res = []
for p in range(r[0], r[1], -1 if r[1] < r[0] else 1):
pa = build_param_array(ranges[1:])
for a in pa:
res.append([p * r[2]] + a)
return res
# range = (start, stop, scale)
ranges = [(1, 5, 1),
(0, 10, .1),
(15, 10, .2)
]
params = build_param_array(ranges)
for p in params:
doFunction(*p)

Mark Element in List

I have an excercise about prime numbers that requires me to write a function which takes a list of elements and a number p and marks elements False which are in the range 2p, 3p...N
First I create a list of True and False:
true_value = [False, False] + [True for x in range(n-1)] #Let assumme that n=16
And then I write the function that find the even number in this list (with p = 2)
def mark_false(bool_list, p):
range_new = [x for x in range(len(bool_list))]
for i in range(2, len(range_new)):
for j in range(p, len(range_new), p):
if (i*p == range_new[j]) & (i*p <= len(range_new)):
bool_list[j] = False
return bool_list
This function help me to find the location of the even number (>2) and return to False
Example: a = list_true(16)
a = [False,False,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True]
b = mark_false(a, 2)
b = [False,False,True,True,False,True,False,True,False,True,False,True,False,True,False,True]
This function mark_false does work but the problem is everytime I run it I have to create a list range_new which takes a lot of time to calculate. So how do I rewrite this function so it can run faster without creating new lists?
You seem to be doing things the long way around, searching for the j value that matches the multiple of p you want to set to False. But since you already know that value already, there's no need to search for it, just set it directly.
I'd do:
def mark_false(bool_list, p):
for i in range(p, len(bool_list), p): # p, 2*p, 3*p, ...
bool_list[i] = False # do the assignment unconditionally
You probably shouldn't need a return statement, since you're modifying the list you are passed in-place. Returning the list could make the API misleading, as it might suggest that the returned list is a new one (e.g. a modified copy).
If you did want to return a new list, you could create one with a list comprehension, rather than modifying the existing list:
def mark_false_copy(bool_list, p):
return [x if i % p else False for i, x in enumerate(bool_list)]

how can i print the right value in the code?

I'm new to python, and I'm having trouble resolving this code. I just have to print the position of the string when j equals r. But it prints nothing.
class List():
def __init__(self, l_red, l_erd, r):
self.l_red = "ABCEFGC"
self.l_erd = "DBFEGAC"
self.r = l_red[0]
def posicao(self):
j = self.l_red[0];
while self.l_erd[j] != self.r:
j = j + 1
print(j)
This is a bit hard to understand but I will give it a go.
To begin with you really need to consider using a different name for the class; List is already in python.
To instantiate and use this class you would need to use:
a_variable = List() # or whatever you are going to use
a_variable.posicao()
l_red is a string which can act like a character list, and l_erd is the same. Lists take an integer number (0, 1, 2, 3 ...) and return what was in that place. So what you need to do is something more like:
def posicao(self):
letter_of_interest = "A"
j = 0
for j in range(0, len(self.l_erd):
if letter_of_interest == self.r:
print(j)
break
Now what I have written is just for a single character, and you would use a loop to go through each character of interest, but I will leave that to you.
If you want it to find all the positions where that character exists just remove that break.
There are better methods of doing this, look into just using "ABCDE".index('A') this works.

How can i optimise my code and make it readable?

The task is:
User enters a number, you take 1 number from the left, one from the right and sum it. Then you take the rest of this number and sum every digit in it. then you get two answers. You have to sort them from biggest to lowest and make them into a one solid number. I solved it, but i don't like how it looks like. i mean the task is pretty simple but my code looks like trash. Maybe i should use some more built-in functions and libraries. If so, could you please advise me some? Thank you
a = int(input())
b = [int(i) for i in str(a)]
closesum = 0
d = []
e = ""
farsum = b[0] + b[-1]
print(farsum)
b.pop(0)
b.pop(-1)
print(b)
for i in b:
closesum += i
print(closesum)
d.append(int(closesum))
d.append(int(farsum))
print(d)
for i in sorted(d, reverse = True):
e += str(i)
print(int(e))
input()
You can use reduce
from functools import reduce
a = [0,1,2,3,4,5,6,7,8,9]
print(reduce(lambda x, y: x + y, a))
# 45
and you can just pass in a shortened list instead of poping elements: b[1:-1]
The first two lines:
str_input = input() # input will always read strings
num_list = [int(i) for i in str_input]
the for loop at the end is useless and there is no need to sort only 2 elements. You can just use a simple if..else condition to print what you want.
You don't need a loop to sum a slice of a list. You can also use join to concatenate a list of strings without looping. This implementation converts to string before sorting (the result would be the same). You could convert to string after sorting using map(str,...)
farsum = b[0] + b[-1]
closesum = sum(b[1:-2])
"".join(sorted((str(farsum),str(closesum)),reverse=True))

k way merge sort divide and conquer

from math import ceil
def merge(all_lst):
sorted_lst = []
while all_lst:
min_value,index = all_lst[0][0],0
for lst in all_lst:
if lst[0]<min_value:
min_value = lst[0]
index = all_lst.index(lst)
sorted_lst.append(min_value)
all_lst[index].pop(0)
if not all_lst[index]:
all_lst.remove(all_lst[index])
return sorted_lst
def merge_sort(lst, k):
def split(lst):
split_lst = []
j = ceil(len(lst)/k) if len(lst)>=k else 1
for i in range(0,len(lst),j):
split_lst.append(lst[i:i+j])
return split_lst
lst=split(lst)
if len(lst[0])==1:
return lst
else:
for i in range(len(lst)):
lst[i]=merge(merge_sort(lst[i],k))
return merge(lst)
Above is my code for k-way merge sort. Basically what it does is split the list into k smaller list by calling the split function until each sublist in the list is a single element. Then the list containing sublists will be merged into one single list.
My code works fine when splitting is done twice. (eg.[3,6,8,5,2,1,4,7] -> [3,6,8],[5,2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]). But when the splitting is done more than twice, (eg,[3,6,8,5,2,1,4,7] -> [3,6,8,5],[2,1,4,7] -> [3,6],[8,5],[2,1],[4,7] -> [3],[6],[8],[5],[2],[1],[4],[7]), the code will fail. Can anyone help find me find out what goes wrong in my code? Thanks in advance.
I believe the problem you're having is that merge_sort sometimes returns a flattened list and other times returns a list of lists. You should probably return a flat list in all cases. There's some other cruft: You don't need split to be its own function, since you only call it the one time.
Here's a greatly simplified version of your code:
def merge_sort(lst, k):
if len(lst) == 1: # simpler base case
return lst
j = ceil(len(lst)/k) # no need to check for k < len(lst) (ceil handles it)
#split and recursively sort in one step
lst = [merge_sort(lst[i:i+j], k) for i in range(0, len(lst), j)]
return merge(lst) # always return a merged list (never a list of lists)

Resources