Automatically pass variables names to list - python

I have a long chain of code for a portion of a script. For example:
B1_2013 = images.select('0_B1')
B2_2013 = images.select('0_B2')
B3_2013 = images.select('0_B3')
B4_2013 = images.select('0_B4')
B5_2013 = images.select('0_B5')
B6_2013 = images.select('0_B6')
B7_2013 = images.select('0_B7')
B8_2013 = images.select('0_B8')
B9_2013 = images.select('0_B9')
B10_2013 = images.select('0_B10')
B11_2013 = images.select('0_B11')
B1_2014 = images.select('1_B1')
B2_2014 = images.select('1_B2')
B3_2014 = images.select('1_B3')
B4_2014 = images.select('1_B4')
B5_2014 = images.select('1_B5')
B6_2014 = images.select('1_B6')
B7_2014 = images.select('1_B7')
B8_2014 = images.select('1_B8')
B9_2014 = images.select('1_B9')
B10_2014 = images.select('1_B10')
B11_2014 = images.select('1_B11')
and so on ...
B11_2020 = images.select('7_B11')
Ultimately, from these lines of code, I need to generate a list of variables (my_variables) that I can pass off to a function. For example:
my_variables = [B1_2013, B2_2013, B3_2013, B4_2013, B5_2013, B6_2013, B7_2013, B8_2013, B9_2013, B10_2013, B11_2013, \
B1_2014, B2_2014, B3_2014, B4_2014, B5_2014, B6_2014, B7_2014, B8_2014, B9_2014, B10_2014, B11_2014]
Is there a more efficient approach to automatically generate hundreds of lines of code (e.g. B1_2013 = images.select('0_B1') and so on...) following the first code example so that I can automatically generate a list of variables in the second code example (e.g. my_variables = [B1_2013, and so on...]?

Just make a list using a loop or list comprehension.
my_images = [images.select(f'{i}_B{j}') for i in range(8) for j in range(12)]

In this use case it is more viable to use a dict to store the "variables" it is not good practice to dynamically build variables. Below is an example using itertools.product that will build a dict with desired output:
from itertools import product
images = {f'B{i}_{y+2013}': images.select(f'{y}_B{i}')
for y, i in product(range(12), range(1, 8))}
Result:
{'B1_2013': '0_B1',
'B2_2013': '0_B2',
'B3_2013': '0_B3',
'B4_2013': '0_B4',
'B5_2013': '0_B5',
'B6_2013': '0_B6',
'B7_2013': '0_B7',
'B1_2014': '1_B1',
'B2_2014': '1_B2',
'B3_2014': '1_B3',
...
}
Then to access the desired "variable" use:
>>> images['B3_2014']
'1_B1'

#Barmar's answer is correct. You can extend his answer if you wanted to index the variables by doing the following:
my_images = {f'{i}_B{j}':images.select(f'{i}_B{j}') for i in range(8) for j in range(12)}
This is called dictionary comprehension.

Or dictionary comprehension:
my_images = {'B{j}_{2013 + i}': images.select(f'{i}_B{j}') for i in range(8) for j in range(12)}
Refer them with:
my_images['B1_2013']
my_images['B2_2013']
...

Related

Split a list of arrays and save each array in a new variable

I have the following function that resamples 100 times a file of ~800 elements:
def resample(arg_array):
all_sets = []
i = 1
while i <= 100:
subset = np.random.choice(arg_array, 100, replace=True)
all_sets.append(subset)
i += 1
return all_sets
This produces a list of arrays with 100 elements each, stored in all_sets.
I need to split this list and save each array into a new variable. Thought about doing list comprehension, but doing set1, set2, ..., set100 = [list comprehension] just doesn't seem very efficient or elegant at all.
Would be great if Python had something like bash where you can generate a new variable name for each pass in a loop.
How about like this?
def resample(arg_array):
for i in range(1, 101):
subset = np.random.choice(arg_array, 100, replace=True)
globals()[f"set{i}"] = subset
Instead of creating a variable for each set you could store them in a dictionary like this.
def resample(arg_array):
sample_map = {}
for n in range(1, 100+1):
subset = np.random.choice(arg_array, 100, replace=True)
sample_map[n] = subset
return sample_map
Or even this
def resample(arg_array):
sample_map = {n:np.random.choice(arg_array, 100, replace=True) for n in range(1, 100+1)}
return sample_map

Converting a string and a int into a variable Python

I am currently creating a loop with sikuli. My problem is that i have a fixed variables that will go up to 15 with only the numbers changing at the end. I was looking for a way to combine the string component that is fixed with the integer which will be variable in the loop but then once concatenated have it identified as the predefined variable at the top of the code.
Any help would be awesome!
Dunning1 = (Pattern("Line 1.png").similar(0.97).targetOffset(445,-2))
Balance1 = (Pattern("Line 1.png").similar(0.97).targetOffset(566,-2))
Select1 = (Pattern("Line 1.png").similar(0.97).targetOffset(38,-1))
Dunning2 = (Pattern("Line 2.png").similar(0.97).targetOffset(442,-1))
Balance2 =(Pattern("Line 2.png").similar(0.97).targetOffset(565,2))
Select2 = (Pattern("Line 2.png").similar(0.97).targetOffset(37,-1))
while n < 3:
DunningX = ("Dunning"+str(n)**
print(DunningX)**
doubleClick(DunningX)
type("c",KEY_CTRL)
doubleClick(DunningX)
type("c",KEY_CTRL)
Dunning1 = Env.getClipboard()
BalanceX = ("Balance"+str(n))
doubleClick(BalanceX)
type("c",KEY_CTRL)
doubleClick(BalanceX)
type("c",KEY_CTRL)
ContractBal = Env.getClipboard()
if Dunning1 == ContractBal:
SelectX = ("Select"+str(n))
click(SelectX)
n = n + 1
I'm not sure if I fully understand your question, but I think you're looking for this:
if some_condition:
Select1 = "Select"+str(n)
else
Select2 = "Select"+str(n)
any way, please consider using a list for this since using single variables is not scalable at all. It could look like this:
select = []
select.append(Pattern("Line 1.png").similar(0.97).targetOffset(38,-1))
select.append(Pattern("Line 2.png").similar(0.97).targetOffset(37,-1))
...
if some_condition:
m=1
else
m=2
select[m] = 'select'+str(n)
From your code shown i see a few issues.
I assume your while n < 3 is indentation issue.
error with (:
DunningX = "Dunning" + str(n)
print(DunningX)
I would recommend you to do the following:
1 - add all the variables to a class as attributes:
class Variables:
def __init__(self):
self.Dunning1 = (Pattern("Line 1.png").similar(0.97).targetOffset(445,-2))
self.Balance1 = (Pattern("Line 1.png").similar(0.97).targetOffset(566,-2))
2 - get the values dynamically by their name using getattr func:
n=1 // for example
vars = Variables()
DunningX = getattr(vars,f"Dunning{n}") //DunningX will be equal to Dunning1

Nested while loop only iterates once

I have written some code which takes data from a csv file, stores it in lists, then iterates over the data returning only the information I need.
I had it working for single lists:
# Import modules
import csv
import datetime
# import numpy as np
import matplotlib.pyplot as plt
# Time code (as slow to run)
tin = []
tout = []
tin = datetime.datetime.now() #tic
plt.close()
# Assign variables
pktime = []
pkey1 = []
pkey2 = []
pkey3 = []
pkey4 = []
pkey5 = []
pkey6 = []
pkeys=[pkey1, pkey2, pkey3, pkey4, pkey5, pkey6]
delt1 = []
delt2 = []
delt3 = []
delt4 = []
delt5 = []
delt6 = []
delts=[delt1, delt2, delt3, delt4, delt5, delt6]
pkey1full=[]
pkey2full=[]
pkey3full=[]
pkey4full=[]
pkey5full=[]
pkey6full=[]
pkeyfull=[pkey1full, pkey2full, pkey3full, pkey4full, pkey5full, pkey6full]
# Read in PK weight/deltaT/time values
with open('PKweight.csv') as pkweight:
red = csv.reader(pkweight)
for t, pk1, pk2, pk3, pk4, pk5, pk6, dt1, dt2, dt3, dt4, dt5, dt6 in red:
pktime.append(datetime.datetime.strptime(t,'%H:%M:%S'))
pkey1.append(float(pk1))
pkey2.append(float(pk2))
pkey3.append(float(pk3))
pkey4.append(float(pk4))
pkey5.append(float(pk5))
pkey6.append(float(pk6))
delt1.append(float(dt1))
delt2.append(float(dt2))
delt3.append(float(dt3))
delt4.append(float(dt4))
delt5.append(float(dt5))
delt6.append(float(dt6))
#calculate the pkweight for each cell, then append it to pkey*full
def pkweight1_calc():
i=1
while i<=(len(pkey1)-1):
if pkey1[i] == 0.0 and pkey1[i-1]!=0.0:
pkey1full.append(pkey1[i-2])
i+=1
pkey1full.reverse()
return pkey1full
pkweight1_calc()
I had this code written out 6 times to complete the function for each of the sets of data(1-6), however I want to have it all as one function. I have tried using a nested while loop within a while loop, however it only returns one of the lists, whatever the inital value of j was:
def pkweight_calc():
i=1
for j in range(0,5):
while i<=(len(pkeys[j])-1):
if (pkeys[j][i]) == 0.0 and (pkeys[j][i-1])!=0.0:
pkeyfull[j].append(pkeys[j][i-2])
i+=1
pkeyfull[j].reverse()
pkweight_calc()
Can anyone help me with this? Thanks in advance!!
EDIT- updated indenting, Sorry!
thanks for the help, I managed to find someone at work who could help me. He wasnt sure why but changing the while loop
while i<=(len(pkeys[j])-1):
to a for loop:
for i in range(2, len(pkeys[j])):
solved it. Not sure why but it did!

performance of calculations on large flattened dictionary with implied hierarchy

Given a dictionary structured like this:
{'guy1_arm_param1':23.0, 'guy1_arm_param2_low':2.0, 'guy1_arm_param2_high':3.0, 'guy1_arm_param3':20.0,
'guy1_leg_param1':40.0, 'guy1_leg_param2_low':2.0, 'guy1_leg_param2_high':3.0, 'guy1_leg_param3':20.0,
'guy2_arm_param1':23.0, 'guy2_arm_param2_low':2.0, 'guy2_arm_param2_high':3.0, 'guy2_arm_param3':20.0,
'guy2_leg_param1':40.0, 'guy2_leg_param2_low':2.0, 'guy2_leg_param2_high':3.0, 'guy2_leg_param3':20.0,
'another_guy_param1':3.0}
What the most efficient way to make a function which will go through and pull out the parameters for a given 'guy' and make a calculation with them?
For example:
def full_guy_function(given_dict, guy):
d = unflatten(given_dict)
guy_functions = list()
guy_dict = {}
for body_part in d[guy].keys():
param1 = d[guy][body_part]['param1']
param3 = d[guy][body_part]['param3']
for k, v in d[guy][body_part]['param2'].iteritems():
guy_functions.append(get_function_for_part(param1, v, param3))
full_guy_function = sum(guy_functions)
return full_guy_function
def get_function_for_part(param1, param2, param3):
x = [x for x in range(0,100)]
x = numpy.array(x)
return param3**(x*param1/param2)
# http://stackoverflow.com/questions/6037503/python-unflatten-dict
def unflatten(dictionary):
resultDict = dict()
for key, value in dictionary.iteritems():
parts = key.split('_')
d = resultDict
for part in parts[:-1]:
if part not in d:
d[part] = dict()
d = d[part]
d[parts[-1]] = value
return resultDict
I feel like looping through and making other dictionaries etc. is horribly inefficient. (this is a big main dictionary, and this function will be called every couple milliseconds.)
I tried to do this using objects which was much more easily understood, but the hierarchical objects cannot be read from different processes than the ones that are using and writing to them. So, I am stuck with trying to make a massive flattened dictionary like this and calculating the results on both sides of the processes.
If this type of operation has to be done every couple of milliseconds on large sets of data, is it better to do with a database?
Better later than never...
I suggest you to use python-benedict, it is open-source on GitHub (I am the author).
Installation: pip install python-benedict
Just test how the flatten dict will be:
from benedict import benedict
data = benedict({
'guy1_arm_param1':23.0, 'guy1_arm_param2_low':2.0, 'guy1_arm_param2_high':3.0, 'guy1_arm_param3':20.0,
'guy1_leg_param1':40.0, 'guy1_leg_param2_low':2.0, 'guy1_leg_param2_high':3.0, 'guy1_leg_param3':20.0,
'guy2_arm_param1':23.0, 'guy2_arm_param2_low':2.0, 'guy2_arm_param2_high':3.0, 'guy2_arm_param3':20.0,
'guy2_leg_param1':40.0, 'guy2_leg_param2_low':2.0, 'guy2_leg_param2_high':3.0, 'guy2_leg_param3':20.0,
'another_guy_param1':3.0,
})
data_unflatten = data.unflatten()
print(data_unflatten.dump())
Your code:
from benedict import benedict
def full_guy_function(given_dict, guy):
b = benedict(given_dict)
d = b.unflatten()
guy_functions = []
guy_dict = {}
for guy_key, guy_val in d.items():
param1 = guy_val['param1']
param3 = guy_val['param3']
for k, v in guy_val['param2'].items():
guy_functions.append(get_function_for_part(param1, v, param3))
full_guy_function = sum(guy_functions)
return full_guy_function
def get_function_for_part(param1, param2, param3):
x = [x for x in range(0,100)]
x = numpy.array(x)
return param3**(x*param1/param2)

Create list from objects in Python

I'm having troubles creating a list from the numbers I made using my code.
ListA = [5,1,3,8,4]
LengthB = (len(ListA))
obj0 = ListA[0]
obj1 = ListA[1]
obj2 = ListA[2]
obj3 = ListA[3]
obj4 = ListA[4]
obj01 = int(obj0)
obj11 = int(obj1)
obj21 = int(obj2)
obj31 = int(obj3)
obj41 = int(obj4)
obj010 = obj01+obj11
obj110 = obj01+obj11+obj21
obj210 = obj11+obj21+obj31
obj310 = obj21+obj31+obj41
obj410 = obj31+obj41
ListBnum0 = (obj010 / 2)
ListBnum1 = obj110 / 3
ListBnum2 = obj210 / 3
ListBnum3 = obj310/ 3
ListBnum4 = obj410 / 2
print(ListBnum0)
print(ListBnum1)
print(ListBnum2)
print(ListBnum3)
print(ListBnum4)
FinalForm1 = str(ListBnum0)
FinalForm2 = str(ListBnum1)
FinalForm3 = str(ListBnum2)
FinalForm4 = str(ListBnum3)
FinalForm5 = str(ListBnum4)
Basically this program takes the ListA numbers and computes the average of the one behind the number, the number and number after if applicable. My real question is how can I take either ListBnum(0) to ListBnum(4) and create another list out of the numbers?
Why does this return an error below?
ListB = list[ListBnum0,ListBnum1,ListBnum2,ListBnum3,ListBnum4]
The direct answer to your question is:
new_list = [ListBnum0, ListBnum1, ListBnum2, ListBnum3, ListBnum4]
The reason you get an error when doing this:
ListB = list[ListBnum0,ListBnum1,ListBnum2,ListBnum3,ListBnum4]
… is that list is a function, and function calls need parentheses to call them. You could write it like this:
ListB = list([ListBnum0,ListBnum1,ListBnum2,ListBnum3,ListBnum4])
However, there's no reason to do so. What the list function does is to take any iterable as an argument, and return a list with the same values. But [ListBnum0, …] is already a list, so you're just making a copy for no reason.
Meanwhile, this whole design is clunky. Better to process the whole list at a time, than to split it into 5 separate variables and process them one by one and merge them back into a list. For example:
ListA = [5,1,3,8,4]
List0 = [int(i) for i in ListA]
def avg(x):
return sum(x) / len(x)
ListB = [avg(List0[max(i-1, 0):i+2]) for i in range(len(List0))]
ListFinal = [str(i) for i in ListB]

Categories