I am working on a program that can be used to add a given value say a car dealership with the cars it owns:
for example
car_storage = []
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
else:
items.append([dealership, car])
return
add_cars("Manchester", "Mini")
add_cars("London", "Toyota")
add_cars("London", "BMW")
add_cars("London", "BMW")
#Desired output
[["Nottingham", "Audi"],["Manchester","Mini"],["London", "Lorry", "BMW", "BMW"]]
However, my code never adds to the list, where am I going wrong?
The issue with your code as #juanpa.arrivillaga said is that the before you add the first item the list car_dealership is empty so nothing in your function executes.
Your approach however is almost correct, Python supports else keyword with for loops. What it means is, if the for loop ran without breaking (no break statements) the else statement is called. For example
for i in range(1, 4):
if i==2:
break
else: # Not executed as there is a break
# if we remove the break the else will run
print("No Break")
Now similarly in your code. you can use the same concept.
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
else:
car_storage.append([dealership, car])
Which is very similar to your original code except the indentation level on the else part.
Now in this case since you're returning and not breaking you can even get away with removing the else entirely since the function will never reach there
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
car_storage.append([dealership, car])
Related
Background information:
hey,
I want to do the following: I have a dictionary with IDs as keys and lists with various things as value. One of the items of the value is a string. I want to check, if a list contains this string. And I want to do it for all keys in my dictionary.
If the list contains the string, I want to print "String is valid"
If the list does not contain the string, I want to print "String is NOT valid"
So far, so good.
Furthermore, the lists I want to check depend on one console input of the user, which specifies, which list should be checked. The console input is "number".
My idea was to iterate over my dictionary and my list with a nested for-loop and compare, if the string(the item of the value) is equal to any list item. If it is, I want to break out of the loop. If the String is not found in the list, I want to execute the else-statement to print my "String is not valid" message.
Code snippet:
def validationHelper(myDict, myList):
for key in myDict:
for value in myDict[key][0]:
for item in myList:
if value==item:
validationHelper.true="String is valid"
break
else:
validationHelper.true="Warning: String is NOT valid"
def validation(anyList,helperfunc):
if anyList=="one":
return helperfunc(finalDict,myList1)
if anyList=="two":
return helperfunc(finalDict,myList2)
if anyList=="three":
return helperfunc(finalDict,myList3)
validation(number, validationHelper)
print(validationHelper.true)
Problem:
I am running this, but no matter if the string is in the list or not, I always get my printout for the else-statement. So, I guess I have an error in reasoning in my for-loop? Or maybe, I did not understand for-loops at all?! I have tried out different indentions with the else-statement, but couldnt solve my problem.
I would suggest you to change your function the following way (without changing the logic):
def validationHelper(myDict, myList):
for key in myDict:
for value in myDict[key][0]:
for item in myList:
if value==item:
return "String is valid" # Add here to exit
return "Warning: String is NOT valid" # will be returned inf nothing will be found in your 3 loops
def validation(anyList,helperfunc):
if anyList=="one":
return helperfunc(finalDict,myList1)
if anyList=="two":
return helperfunc(finalDict,myList2)
if anyList=="three":
return helperfunc(finalDict,myList3)
validation(number, validationHelper)
print(validationHelper)
This will help you to exit your 3 nested loops as it was mentioned in comments.
Because in the negative case on first wrong occurrence you don't need to check anything else.
Use return to break all of your loop. Having an else statement is not necessary if you don't have any if statement to begin with.
def validationHelper(myDict, myList):
for item in myList:
if item in myDict.values():
return ("String is valid")
return ("String is NOT valid")
def validation(anyList,helperfunc):
if anyList=="one":
return helperfunc(finalDict,myList1)
elif anyList=="two":
return helperfunc(finalDict,myList2)
elif anyList=="three":
return helperfunc(finalDict,myList3)
validation(number, validationHelper)
print(validationHelper.true)
Using elif instead of multiple if is a better practice. Be careful with indentions next time.
Also you might want to check .keys() and .values()
You can replace:
for key in myDict:
for value in myDict[key][0]:
with:
for value in myDict.values():
The other answers give a good explanation of how to break out of multiple loops. But you could also simplify your code by using Python's built-in functions and list comprehensions, like this:
def validationHelper(myDict, myList):
if any(v in myList for val in myDict.values() for v in val[0]):
validationHelper.true="String is valid"
else:
validationHelper.true="Warning: String is NOT valid"
def validation(anyList,helperfunc):
if anyList=="one":
return helperfunc(finalDict,myList1)
if anyList=="two":
return helperfunc(finalDict,myList2)
if anyList=="three":
return helperfunc(finalDict,myList3)
validation(number, validationHelper)
print(validationHelper.true)
This should be as efficient as your code, since any short circuits at the first match. And it may be a little more readable. (Note that multi-level list comprehensions go in the same order as regular for loops.)
I have a list of dictionaries that is initialised by a call to a function with:
new = {'device_id':name,'device_mac':mac, 'device_ttl':ttl}
dev[0] = new
Thereafter, new entries are appended with:
dev.append(new)
Each dictionary has a time to live (TTL). Once that is reached the dictionary is removed:
for i in dev:
if (i['device_ttl'] == 0):
dev.remove(i)
This all seems fine until the list is completely empty. If I then try and add a new entry with:
dev[0] = new
again, I get a 'list index out of range' error.
I've tried changing the original initialisation with an append to an empty list, but that bombs out immediately with a KeyError: device_id.
The entire function that adds entries is:
# Adds a new device to the list of known devices.
def add_device(dev, num, name, mac, ttl):
new = {'device_id':name,'device_mac':mac, 'device_ttl':ttl}
if (num == 0):
#dev.append(new)
#dev = new
dev[0] = new
else:
dev.append(new)
return (num + 1)
The essential part of the main routine is:
devices = [{}] # Empty list.
num_devices = 0
# Code that determines whether to add to the list or not
num_devices = add_device(devices, num_devices,\
name_long, mac_address, ttl_n)
I don't understand why initialising by appending to an empty list is problematic, nor why what does work to initialise, doesn't work when the list is empty. It is created as empty in the first place!
Is there a better way to initialise or append to an empty list?
The answer was to not declare an empty list of dictionaries ,but just an empty list. A number of respondents pointed out the error but did not elucidate an answer.
Declaring an empty list of dictionaries with:
devices=[{}]
Creates an empty list with an empty dictionary. Assigning the first dictionary with:
dev[0] = new
just replaced the empty dictionary. Hence why the same assignment doesn't work when the list is emptied.
The correct initialisation was to just declare:
devices = []
Adding any dictionary after that, including the first one, is by using an append in the function:
dev.append(new)
Thanks for all of the pointers. I found the answer by switching IDE from Atom to Idle for testing. I have to use Atom as it is the only IDE with the PyCom plugin. Idle flagged the error almost immediately.
I have a function as follows:
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
global qstatnum
qstatnum = {}
qstatnum[gatnum] = []
qstatnum[gatnum].append(qstat) #seems to be a problem
return qstat
However, there is a problem. Let's say I run it once. There will be one item in the list. Then, I run it a second time, with an item distinguishable from the second supposed to be added to the list. When I print qstatnum[gatnum], the list contains only the second item, leading me to believe that the .append() statement is somehow incorrectly written and overwriting any previous additions to the list.
Is this a correct diagnosis? Why would this be? Any help would be appreciated. Thanks!
Each time you call the function, you are creating a new qstatnum dict, so the solution is to create the dictionary outside the function:
qstatnum = {}
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
try:
qstatnum[qstat].append(gatnum)
except:
qstatnum[qstat] = [gatnum]
return qstat
You need a try: except: block to verify if the key already exists in the dictionary, if it doesn't exists, just add the first value, else use append.
#DanD. approach seems to be shorter, please take a look:
qstatnum = {}
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
qstatnum.setdefault(qstat, []).append(gatnum)
return qstat
Every time the method is called, qstatnum is set to empty. So basically you are appending to nothing every time.
I have a program where the user should be able to pick and choose commands from a drop down list. In this list, there is also a repeat command, which does basically what a for loop does, so all the commands in between repeat and end repeat should be looped the number of times stated. See picture:
Now, I don't yet know how to programatically handle the repeat-functions. I know that python handles classes like objects, so maybe that can help, but I'm a bit lost.
At the moment I send a list of strings to the thread that handles execution of the commands, and that is parsed and each command is executed.
def command(self, item):
if item.startswith('Pan'):
... do stuff
elif item.startswith('...'):
... do something else
How would I rewrite this so that repeat is a callable function/method ?
Make a function multi_command which takes multiple commands, and executes them in order.
When this function encounters a "repeat", create a list of all the following commands up until you get the corresponding "end repeat". This new list is then a sub-set of your total list. Call multi_command with this list, and afterwards, skip to the command that comes after the "end repeat".
Psuedo-code:
def multi_commands(items):
highest_idx_already_done = 0
for idx, item in enumerate(items):
if highest_idx_already_done > idx:
continue
if item == "repeat":
num_repeats = ...
sub_items = []
for sub_item in items[idx+1:]:
if sub_item == "end repeat":
break
sub_items.append(sub_item[5:]) # Skip indentation
highest_idx_already_done = idx + len(sub_items)
for _ in range(num_repeats):
multi_commands(sub_items)
else:
command(item)
In web2py I have been trying to break down this list comprehension so I can do what I like with the categories it creates. Any ideas as to what this breaks down to?
def menu_rec(items):
return [(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)) for x in items or []]
In addition the following is what uses it:
response.menu = [(SPAN('Catalog', _class='highlighted'), False, '',
menu_rec(db(db.category).select().as_trees()) )]
So far I've come up with:
def menu_rec(items):
for x in items:
return x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children))
I've got other variations of this but, every variation only gives me back 1(one) category, when compared to the original that gives me all the categories.
Can anyone see where I'm messing this up at? Any and all help is appreciated, thank you.
A list comprehension builds a list by appending:
def menu_rec(items):
result = []
for x in items or []:
url = URL('shop', 'category', args=pretty_url(x.id, x.slug))
menu = menu_rec(x.children) # recursive call
result.append((x.title, None, url, menu))
return result
I've added two local variables to break up the long line somewhat, and to show how it recursively calls itself.
Your version returned directly out of the for loop, during the first iteration, and never built up a list.
You don't want to do return. Instead append to a list and then return the list:
def menu_rec(items):
result = []
for x in items:
result.append(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)))
return result
If you do return, it will return the value after only the first iteration. Instead, keep adding it to a list and then return that list at the end. This will ensure that your result list only gets returned when all the values have been added instead of just return one value.