Python insert missing elements in array - python

I have an array in the following format:
[(u'iapsetting', 0), (u'iap-mms',0)]
The array must contain only tuples of this type:
(u'mmssetting', 0) or (u'iapsetting', 0) or (u'iap-mms', 0)
My first array is obviously missing the (u'mmssetting',0) but it could many different combinations of missing/existing tuples.
I am struggling to find a way to add the correct missing tuples. The array must always contain only 3 tuples.
This is what I have so far but it is not working as expected:
for type in setup: #setup is the array containing 1,2 or 3 tuples
iap_found = False
mms_found = False
iap_mms_found = False
if type[0]=='iapsetting':
iap_found = True
elif type[0]=='mmssetting':
mms_found = True
elif type[0]== 'iap-mms':
iap_mms_found = True
#Add missing settings
if(iap_found==False):
print("MISSING IAP",setup)
setup.append((u'iapsetting',0))
elif(mms_found==False):
print("MISSING MMS",setup)
setup.append((u'mmssetting',0))
elif(iap_mms_found==False):
print("MISSING IAP-MMS",setup)
setup.append((u'iap-mms',0))
Any help will be greatly appreciated because there might be a much better way of doing this. Thank you.
Sara

Try this:
existing = set(x[0] for x in setup)
for expected in ('iapsetting', 'mmssetting', 'iap-mms'):
if expected not in existing:
setup.append((expected, 0))

What you were doing wrong were mainly two things:
you initialized the flags inside the loop.
you started adding missing settings before you finished looping through the whole array.
# Initialize flags before entering loop:
iap_found = False
mms_found = False
iap_mms_found = False
for type in setup: #setup is the array containing 1,2 or 3 tuples
if type[0]=='iapsetting':
iap_found = True
elif type[0]=='mmssetting':
mms_found = True
elif type[0]== 'iap-mms':
iap_mms_found = True
#Add missing settings after looping through the whole array:
if(iap_found==False):
print("MISSING IAP",setup)
setup.append((u'iapsetting',0))
if(mms_found==False):
print("MISSING MMS",setup)
setup.append((u'mmssetting',0))
if(iap_mms_found==False):
print("MISSING IAP-MMS",setup)
setup.append((u'iap-mms',0))

Instead of using if ... elif .. elif you should use
if not iap_found:
print("MISSING IAP",setup)
setup.append((u'iapsetting',0))
if not mms_found:
print("MISSING MMS",setup)
setup.append((u'mmssetting',0))
if not iap_mms_found==False:
print("MISSING IAP-MMS",setup)
setup.append((u'iap-mms',0))
The problem of if .. elif is that only one branch will get executed.
For other solutions, different (and in this case also better) than if, see the other anwers

I think sets represent this logic most clearly. Use a set comprehension to extract the strings.
REQUIRED_VALUES = {"mmssetting", "iapsetting", "iap-mms"}
input_tuple_list = [(u'mmssetting', 1), (u'iap-mms', 3)]
# set comprehension paired with set difference -- results in {"iapsetting"}
missing_values = REQUIRED_VALUES - {val for val, count in input_tuple_list}
# results in [(u'mmssetting', 1), (u'iap-mms', 3), (u'iapsetting', 3)]
input_tuple_list.extend((val, 0) for val in missing_values)

Related

I need help trying to find a different value in a list

I am trying to make a maze generator, I am currently trying to spread out the objects evenly without having them overlap. I have already made a function that snaps the coords to a grid. The grid snap is 50 at the moment. What I am having trouble with is trying to make it so that I coords don't overlap. EX: If I already have an object at (100, 100), I dont want another object to go to (100, 100). If you would like the whole file, I can give it to you, but stack overflow wont allow that. The code included for some reason does not work, it really seams like it should though.
objectXLst = []
objectYLst = []
objectXYLst = [(1, 1)]
def check_list(listToCheck, valToCheck):
objectX = valToCheck[0]
objectY = valToCheck[1]
objectXY = valToCheck
for i in range(len(listToCheck)):
while listToCheck[i] == objectXY:
resultForCheck = True
objectX = divisible_random(0, screenWidth, gridSnapVal)
objectY = divisible_random(0, screenHeight, gridSnapVal)
objectXY = (objectX, objectY)
print("{}, {}, checking".format((objectX, objectY), valToCheck), listToCheck[i])
else:
break
return objectX, objectY
for i in range(int((screenWidth*screenHeight)/gridSnapVal**2)):
index = 0
objectX = divisible_random(0, screenWidth, gridSnapVal)
objectY = divisible_random(0, screenHeight, gridSnapVal)
counter = 0
goThru = True
val = check_list(objectXYLst, (objectX, objectY))
objectX, objectY = check_list(objectXYLst, (objectX, objectY))
counter = 0
if remove1st is True:
objectXYLst.remove((1, 1))
remove1st = False
print(objectX, objectY)
objectXLst.append(objectX)
objectYLst.append(objectY)
objectXYLst.append((objectX, objectY))
gameObjectsList.append(gameObjects)
Not withstanding Ethan's comments above which would help us give better answers, it looks like the first part of your code could be made substantially simpler by using Python sets and testing membership of these. This is much faster and easier than iterating through the list manually.
e.g.
#set with all the coordinates already used:
>>> s = {(1,1), (2,1), (3,4)}
# test different coordinates for membership of s
>>> (1,1) in s
True
>>> (4,5) in s
False

Extracting Gurobi Solution Index

I have a bunch of gurobi variables
y[0],y[1],...,y[n]
x[0],x[1],...,x[m].
I would like to be able to figure out the indices of the optimal y's that are not zero. In other words, if the optimal solution is y[0]=0, y[1]=5, y[2]=0, y[3]=1, I would like to return [1,3]. So far, I have
F = []
for v in model.getVars():
if v.varName[0]=='y' and v.x>0:
F.append[v.varName]
This, in the above example, would give me ['y[1]', 'y[3]']. Since this output is a string, I'm not sure how I can get the 1 and 3 out of it. Please help.
Thanks in advance!
I am using the following which works:
Index_List = []
for v in m.getVars():
if v.varName[0] == 'y' and v.x>0:
Index = int(v.varName[2])
for j in range(3,3+100)):
BOOL = False
try:
IndexNEW =int(v.varName[j])
Index = 10*Index+IndexNEW
BOOL = True
except ValueError:
()
if not BOOL:
break
Index_List.append(Index)
The resulting Index_List is as desired. There must be a better way though.
Assuming
from gurobipy import *
m = Model()
If you create a gurobi tupledict for your variables with
x = m.addVars(nx, vtype=GRB.INTEGER, name="x")
y = m.addVars(ny, vtype=GRB.INTEGER, name="y")
# ...your constraints and objective here..
then you can directly call the attributes for your variables (in your case the .X attribute for the variable value in the current solution). Using a list comprehension it could be done with:
m.optimize()
if m.status == GRB.OPTIMAL:
indices = [i for i in range(ny) if y[i].X > 0]
where nx and ny are the number of your variables.

Python Creating a dictionary of dictionaries structure, nested values are the same

I'm attempting to build a data structure that can change in size and be posted to Firebase. The issue I am seeing is during the construction of the data structure. I have the following code written:
for i in range(len(results)):
designData = {"Design Flag" : results[i][5],
"performance" : results[i][6]}
for j in range(len(objectiveNameArray)):
objectives[objectiveNameArray[j]] = results[i][columnHeaders.index(objectiveNameArray[j])]
designData["objectives"] = copy.copy(objectives)
for k in range(len(variableNameArray)):
variables[variableNameArray[k]] = results[i][columnHeaders.index(variableNameArray[k])]
designData["variables"] = copy.copy(variables)
for l in range(len(responseNameArray)):
responses[responseNameArray[l]] = results[i][columnHeaders.index(responseNameArray[l])]
designData["responses"] = copy.copy(responses)
for m in range(len(constraintNameArray)):
constraintViolated = False
if constraintNameArray[m][1] == "More than":
if results[i][columnHeaders.index(constraintNameArray[m][0])] > constraintNameArray[m][2]:
constraintViolated = True
else:
constraintViolated = False
elif constraintNameArray[m][1] == "Less than":
if results[i][columnHeaders.index(constraintNameArray[m][0])] < constraintNameArray[m][2]:
constraintViolated = True
else:
constraintViolated = False
if constraintNameArray[m][0] in constraints:
if constraints[constraintNameArray[m][0]]["violated"] == True:
constraintViolated = True
constraints[constraintNameArray[m][0]] = {"value" : results[i][columnHeaders.index(constraintNameArray[m][0])], "violated" : constraintViolated}
designData["constraints"] = copy.copy(constraints)
data[studyName][results[i][4]] = designData
When I include print(designData) inside of the for loop, I see that my results are changing as expected for each loop iteration.
However, if I include print(data) outside of the for loop, I get a data structure where the values added by the results array are all the same values for each iteration of the loop even though the key is different.
Comparing print(data) and print(designData)
I apologize in advance if this isn't enough information this is my first post on Stack so please be patient with me.
It is probably because you put the variables like objectives, variables, responses directly to the designData. Try the following:
import copy
....
designData['objectives'] = copy.copy(objectives)
....
designData['variables'] = copy.copy(variables)
....
designData['responses'] = copy.copy(responses)
For similar questions, see copy a list.

Print FormatList Issue

I'm just having a small issue of formatting right now. My current code prints out my out in a wonky way and I'm trying to make it look smoother. How would I change my print formatting?
height = {}
length = len(preys)
rank = 0
while preys != [None]*length:
for index,(animal,prey) in enumerate(zip(animals,preys)):
if prey not in animals:
try:
if height[prey] < rank:
height[prey] = rank
except KeyError:
height[prey] = 0
height[animal] = height[prey] + 1
preys[index] = None
animals[index] = None
rank += 1
for arg in sys.argv:
print (sorted (height.items(),key = lambda x:x[1],reverse=True))
if name == "main":
main()
The output looks like this:
[('Lobster', 4), ('Bird', 4), ('Fish', 3), ('Whelk', 3), ('Crab', 3), ('Mussels', 2), ('Prawn', 2), ('Zooplankton', 1), ('Limpets', 1), ('Phytoplankton', 0), ('Seaweed', 0)]
and I'm trying to make it look like:
Heights:
Bird: 4
Crab: 3
Fish: 3
Limpets: 1
Lobster: 4
Mussels: 2
Phytoplankton: 0
Prawn: 2
Seaweed: 0
Whelk: 3
Zooplankton: 1
I've attempted to use the: print(formatList(height)), format however printing anything before the "height" causes errors
Since the output only prints once, we know that sys.argv wasn't passed any extra arguments. There's no need to create a loop that will only be executed once (and, if there were multiple arguments, it isn't generally useful to print the same output several times). Instead, loop over the height object itself.
You are also currently sorting by value, when it's obvious that you want to sort by key. Since the latter is the default sort anyway, I'm not sure why you added (messy) code to sort by value.
Use string formatting to express the appearance you want for each item.
print('Heights:')
for item in sorted(height.items()):
print('{}: {}'.format(*item))
Note that sorting an iterable of tuple objects will sort by the first element first, and then, if there are two tuples with the same first item, they will be sorted by the second element. For example, ('Bird', 1) would come before ('Bird', 2). Since dictionaries can't have duplicate keys, this won't be an issue here, but it's something to keep in mind.
I think you can try something like this:
sorted_ list = sorted (height.items(),key = lambda x:x[1],reverse=True)
print(''.join('%s : %s\n' % x for x in sorted_list))
Or in one expression(if it is not ugly for you):
print(''.join('%s : %s\n' % x
for x in sorted (height.items(),key = lambda x:x[1],reverse=True)))

Looping over dataset of strings

I'm trying to pick out specific occurrences of a value in a dataset of mine, but keep running into a problem dealing with turning the values into strings and looping over them. My code is below:
data = np.genfromtxt('DurhamAirMass.txt')
spot = data[:,1]
mass = str(data[:,2])
DP = np.array([])
DT = np.array([])
MP = np.array([])
MT = np.array([])
TR = np.array([])
for i in range(1461):
if mass[i] == '2':
DP = np.append(DP, str(spot[i]))
if mass[i] == '3':
DT = np.append(DT, str(spot[i]))
if mass[i] == '5':
MP = np.append(MP, str(spot[i]))
if mass[i] == '6' or '66' or '67':
MT = np.append(MT, str(spot[i]))
if mass[i] == '7':
TR = np.append(TR, str(spot[i]))
print DP
When I attempt to print out the DP array, I get an error pointing at the first if statement and saying "IndexError: string index out of range". Any ideas?
What is the purpose of converting data[:,2] into a string?
Btw. or does not work as you think, you have to repeat `mass[i]==``
Why not:
data = np.genfromtxt('DurhamAirMass.txt')
mass = data[:, 1]
spot = data[:, 2]
DP = mass[spot == 2]
DT = mass[spot == 3]
MP = mass[spot == 5]
MT = mass[(spot == 6)||(spot == 66)||(spot == 67)]
TR = mass[spot == 7]
As a general rule, you should never hard-code for-loop iterations unless you want it to be considered an error for the input iterator to ever be greater/smaller than your hard-coded value (and even then, there are better ways to accomplish that).
Your code should probably look like this:
for i in range(len(data)):
...
This will ensure you always loop over only the data you actually have.
You are indeed causing an IndexError
try checking spot to see how large it is, my guess is that 1461 is larger then its bounds perhaps you could try setting your for loop as:
for i in range(len(spot)):
...
instead, this will garauntee that you will only access valid Indexes for spot, if this still causes a problem try the same for mass
for i in range(len(mass)):
...
You could also add a check to make sure the data is the length you think it is.
print len(mass), len(spot), len(spot) == len(mass)
It's always good practice to double check your assumptions in the case of an error. In this case you are clearly being told there is an IndexError so the next step is to find out what index is causing it.
Maybe more information would help you?
try:
for i in range(len(spot)):
# code as usual
except:
print i
raise e
This will tell you what index is causing the error.
I just changed all the strings to ints and that solved things. I didn't think that would work at first. Thanks for all of your answers, everyone!

Categories

Resources