In short i have a list of items. lets say they have a name of Object1, Object2,....Object10,....Object20 And so on.
This list depending on use input changes starting points, for the example lets say the list packs in the names of all objects from Object18 up to Object28
Im using a statement to select these items from the stored list that goes:
for i in nuke.allNodes():
if i.name() in hiddenLists:
i.setSelected(True)
else:
i.setSelected(False)
Which works generally... trouble is because "in" (for inside the list) doesnt specify i want it to have to match an entire entry of the list, Instead of JUST selecting Object 18-28 it selects Object1 Object2 And Object 18-28 (reason being of course, Object18 and so on begin with Object1, and the 20s with a 2)
I cant pad the strings due to the fact that these are set names a program creates and have to stay the same. my only question is, is there a better operator than in that makes it have to match exactly rather than see Object1 within 'Object18'?
Looks like hiddenLists is a string (str) entered by the user. Use the split method on that string to make it a list first. Then the "in" clause will do what you want.
For instance, if the user enters a comma-separated list:
hiddenLists = [x.strip() for x in hiddenLists.split(",")]
if i.name() in hiddenLists:
...
Related
I've searched around and most of the errors I see are when people are trying to iterate over a list and modify it at the same time. In my case, I am trying to take one list, and remove items from that list that are present in a second list.
import pymysql
schemaOnly = ["table1", "table2", "table6", "table9"]
db = pymysql.connect(my connection stuff)
tables = db.cursor()
tables.execute("SHOW TABLES")
tablesTuple = tables.fetchall()
tablesList = []
# I do this because there is no way to remove items from a tuple
# which is what I get back from tables.fetchall
for item in tablesTuple:
tablesList.append(item)
for schemaTable in schemaOnly:
tablesList.remove(schemaTable)
When I put various print statements in the code, everything looks like proper and like it is going to work. But when it gets to the actual tablesList.remove(schemaTable) I get the dreaded ValueError: list.remove(x): x not in list.
If there is a better way to do this I am open to ideas. It just seemed logical to me to iterate through the list and remove items.
Thanks in advance!
** Edit **
Everyone in the comments and the first answer is correct. The reason this is failing is because the conversion from a Tuple to a list is creating a very badly formatted list. Hence there is nothing that matches when trying to remove items in the next loop. The solution to this issue was to take the first item from each Tuple and put those into a list like so: tablesList = [x[0] for x in tablesTuple] . Once I did this the second loop worked and the table names were correctly removed.
Thanks for pointing me in the right direction!
I assume that fetchall returns tuples, one for each database row matched.
Now the problem is that the elements in tablesList are tuples, whereas schemaTable contains strings. Python does not consider these to be equal.
Thus when you attempt to call remove on tablesList with a string from schemaTable, Python cannot find any such value.
You need to inspect the values in tablesList and find a way convert them to a strings. I suspect it would be by simply taking the first element out of the tuple, but I do not have a mySQL database at hand so I cannot test that.
Regarding your question, if there is a better way to do this: Yes.
Instead of adding items to the list, and then removing them, you can append only the items that you want. For example:
for item in tablesTuple:
if item not in schemaOnly:
tablesList.append(item)
Also, schemaOnly can be written as a set, to improve search complexity from O(n) to O(1):
schemaOnly = {"table1", "table2", "table6", "table9"}
This will only be meaningful with big lists, but in my experience it's useful semantically.
And finally, you can write the whole thing in one list comprehension:
tablesList = [item for item in tablesTuple if item not in schemaOnly]
And if you don't need to keep repetitions (or if there aren't any in the first place), you can also do this:
tablesSet = set(tablesTuple) - schemaOnly
Which is also has the best big-O complexity of all these variations.
I am making a program that works on chat files under the following general form:
Open file & import lines (via readlines)
Do an initial pass to turn the list of strings into better-formed data (currently dicts) by:
Throwing out out malformed lines
Separating out the usernames from the text of the message
Throwing out lines for ignored (typically bot) users
Marking which lines are /me commands
Do a second pass over the list of dicts to apply various manipulations on them, such as:
Replacing every mention of a nick with its alias
Applying special formatting to /me commands
Rather than have multiple switches in the config file and lots of if statement checks within the loops, I believe the program would be cleaner if I generated the list of functions elsewhere and then fed the program the list of dicts (or strings, depending on which part of the program I'm at) and a list of functions such that the list of functions gets applied to each of the items in the list of objects.
It seems that this probably would be a good case for list comprehensions if I were only applying a single function to each item, but I don't want to have to do a separate pass through the log for every function that I want to call. However, this answer notes that list comprehension probably aren't what I want, since they return a completely new list, rather than modifying in place.
Is my best option to have two variants of the following?
for item in list:
item = a(b(c(d(item, dparam1, dparam2), cparam)), aparams)
(for readability, I'd put each function on its own line, like:
for item in list:
item = d(item, dparam1, dparam2)
item = c(item, cparam)
item = b(item)
item = a(item, aparams)
However, the above doesn't eliminate the need for if checks on all the switches and wouldn't allow for applying function a at two different places unless I explicitly add a switch to do so.
Based on your sample code, you may try this way,
func_list = [d, c, b, a]
for idx, item in enumerate(item_list):
item_list[idx] = reduce(lambda v, func: func(v), func_list, item)
Let each func handle the data, make the loop more like pipeline.
What I have is a dictionary of words and I'm generating objects that contain
(1) Original word (e.g. cats)
(2) Alphabetized word (e.g. acst)
(3) Length of the word
Without knowing the length of the longest word, is it possible to create an array (or, in Python, a list) such that, as I scan through the dictionary, it will append an object with x chars into a list in array[x]?
For example, when I encounter the word "a", it will append the generated object to the list at array[1]. Next, for aardvark, if will append the generated object to the list at array[8], etc.
I thought about creating an array of size 1 and then adding on to it, but I'm not sure how it would work.
Foe example: for the first word, a, it will append it to the list stored in array[1]. However, for next word, aardvark, how am I supposed to check/generate more spots in the list until it hits 8? If I append to array, I need give the append function an arg. But, I can't give it just any arg since I don't want to change previously entered values (e.g. 'a' in array[1]).
I'm trying to optimize my code for an assignment, so the alternative is going through the list a second time after I've determined the longest word. However, I think it would be better to do it as I alphabetize the words and create the objects such that I don't have to go through the lengthy dictionary twice.
Also, quick question about syntax: listOfStuff[x].append(y) will initialize/append to the list within listOfStuff at the value x with the value y, correct?
Store the lengths as keys in a dict rather than as indexes in a list. This is really easy if you use a defaultdict from the collections module - your algorithm will look like this:
from collections import defaultdict
results = defaultdict(list)
for word in words:
results[len(word)].append(word)
This ties in to your second question: listOfStuff[x].append(y) will append to a list that already exists at listofStuff[x]. It will not create a new one if that hasn't already been initialised to a (possibly empty) list. If x isn't a valid index to the list (eg, x=3 into a listOfStuff length 2), you'll get an IndexError. If it exists but there is something other than another list there, you will probably get an AttributeError.
Using a dict takes care of the first problem for you - assigning to a non-existent dict key is always valid. Using a defaultdict extends this idea to also reading from a non-existent key - it will insert a default value given by calling the function you give the defaultdict when you create it (in this case, we gave it list, so it calls it and gets an empty list) into the dict the first time you use it.
If you can't use collections for some reason, the next best way is still to use dicts - they have a method called setdefault that works similarly to defaultdicts. You can use it like this:
results = {}
for word in words:
results.setdefault(len(word), []).append(word)
as you can see, setdefault takes two arguments: a key and a default value. If the key already exists in the dict, setdefault just returns its current value as if you'd done results[key]. If that would be an error, however, it inserts the second argument into the dictionary at that key, and then returns it. This is a little bit clunkier to use than defaultdict, but when your default value is an empty list it is otherwise the same (defaultdict is better to use when your default is expensive to create, however, since it only calls the factory function as needed, but you need to precompute it to pass into setdefault).
It is technically possible to do this with nested lists, but it is ugly. You have to:
Detect the case that the list isn't big enough
Figure out how many more elements the list needs
Grow the list to that size
the most Pythonic way to do the first bit is to catch the error (something you could also do with dicts if setdefault and defaultdict didn't exist). The whole thing looks like this:
results = []
for word in words:
try:
results[len(word)]
except IndexError:
# Grow the list so that the new highest index is
# len(word)
new_length = len(word) + 1
difference = len(results) - new_length
results.extend([] for _ in range(difference))
finally:
results[len(word)].append(word)
Stay with dicts to avoid this kind of mess. lists are specifically optimised for the case that the exact numeric index of any element isn't meaningful outside of the list, which doesn't meet your use case. This type of code is really common when you have a mismatch between what your code needs to do and what the data structures you're using are good at, and it is worth learning as early as possible how to avoid it.
I'm working with the Flask framework in Python, and need to hand off a list of lists to a renderer.
I step through a loop and create a list, sort it, append it to another list, then call the render function with the masterlist, like so:
for itemID in itemsArray:
avgQuantity = getJitaQuantity(itemID)
lowestJitaSell = getJitaLowest(itemID)
candidateArray = findLowestPrices(itemID, lowestJitaSell, candidateArray, avgQuantity)
candidateArray.sort()
multiCandidateArray.append(candidateArray)
renderPage(multiCandidateArray)
My problem is that I need to clear the candidateArray and create a new one each time through the loop, but it looks like the candidateArray that I append to the multiCandidateArray is actually a pointer, not the values themselves.
When I do this:
for itemID in itemsArray:
avgQuantity = getJitaQuantity(itemID)
lowestJitaSell = getJitaLowest(itemID)
candidateArray = findLowestPrices(itemID, lowestJitaSell, candidateArray, avgQuantity)
candidateArray.sort()
multiCandidateArray.append(candidateArray)
**del candidateArray[:]**
renderPage(multiCandidateArray)
I end up with no values.
Is there a way to handle this situation that I'm missing?
I would probably go with something like:
for itemID in itemsArray:
avgQuantity = getJitaQuantity(itemID)
lowestJitaSell = getJitaLowest(itemID)
candidateArray = findLowestPrices(itemID, lowestJitaSell, candidateArray, avgQuantity)
multiCandidateArray.append(sorted(candidateArray))
No need to del anything here, and sorted returns a new list, so even if FindLowestPrices is for some reason returning references to the same list (which is unlikely), then you'll still have unique lists in the multiCandidateArray (although your unique lists could hold references to the same objects).
Your code already creates a new one each time through the loop.
candidateArray = findLowestPrices(...)
This assigns a new list to the variable, candidateArray. It should work fine.
When you do this:
del candidateArray[:]
...you're deleting the contents of the same list you just appended to the master list.
Don't think about pointers or variables; just think about objects, and remember nothing in Python is ever implicitly copied. A list is an object. At the end of the loop, candidateArray names the same list object as multiCandidateArray[-1]. They're different names for the same thing. On the next run through the loop, candidateArray becomes a name for a new list as produced by findLowestPrices, and the list at the end of the master list is unaffected.
I've written about this before; the C way of thinking about variables as being predetermined blocks of memory just doesn't apply to Python at all. Names are moved onto values, rather than values being copied into some fixed number of buckets.
(Also, nitpicking, but Python code generally uses under_scores and doesn't bother with types in names unless it's really ambiguous. So you might have candidates and multi_candidates. Definitely don't call anything an "array", since there's an array module in the standard library that does something different and generally not too useful. :))
I am writing a program in python and I am using a dictionary. I need to create an empty list for each key in the dictionary, and each list needs to have the same name as the key. The keys are user entered, which is why I can't just make a list in the conventional way.
This was the first thing I tried
a = {"x":1, "y":2, "z"3}
list(a.keys())
a.pop() = [] # This raises an error
I also tried to make the lists when the dictionary was being created, but this did not work either:
a = {}
b = input("INPUT1")
c = input("INPUT2")
a[b] = c
b = []
This created a list with the name "b" rather than whatever the user entered. Please help!!
This really doesn't make much sense. Why do your lists need 'names'? For that matter, what do you mean by 'names'?
Secondly, your code doesn't do anything. a.keys() is already a list. Calling list on it doesn't do anything else. But in any case, whatever the result of that line is, it is immediately thrown away, as you don't store the result anywhere.
pop doesn't work on dictionaries, it works on lists. And what does it mean to set the result of pop to a list? Are you trying to dynamically create a set of local variables with the names of each key in the dictionary? If so, why? Why not simply create another dictionary with the keys of the first, and each value as a new list? That can be done in one command:
b = dict((k, []) for k in b.keys())
(Note that dict.fromkeys() won't work here, as that would cause each element to share the same list.)
Use raw_input instead. input expects a valid Python expression and WILL evaluate whatever the user inputs. So if the user inputs a word, it'll evaluate that word and try to find an object with its name.
EDIT: for further clarification, input("INPUT1") is the equivalent of doing eval(raw_input("INPUT1")), for instance.