Iterator value not retained after 'any()' call - python

I have the following snippet of code. I'm basically trying to get the index/iterator of a particular string in a list (aside from just knowing whether it is present). Is this possible at all, or should I be using a loop-with-an-if?
bucket = ["alpha", "beta", "gamma"]
content = ""
if any(content == "beta" for content in bucket):
print content
Having 'content' as global or simply within the loop did not make a difference

Generator expressions do not leak the iterator. List comprehensions in 2.x do, but not in 3.x.

You are creating a generator for searching within the any call. That generator as you have left it is a temporary. That is, it exists only within the call to any so you will not be able to look at it afterwards. If you want it to come out to the location of the index then do this:
item = [x for x in enumerate(bucket) if x[1] == "beta"]
which generates the list of all items which match plus the indexes.

Related

Appending to multiple lists in a function - python

I have code that gets information from iTunes based on a search term that returns a list of dictionaries with various media types in it. I would like to group this information by whether or not it is a movie, song, or other media type. I want to do this within a function for later use, and was thinking the best way to do this would be to append each dictionary to a list based on what type it is. I am getting empty lists, even though the input I am putting in the function is a list of 100 dictionaries. Is there a better way to do this? This is my code -
def make_object(list_from_req):
movie_lst = []
song_lst = []
media_other_lst = []
for d in list_from_req:
if d['kind'] == 'song':
song_lst.append
elif d['kind'] == 'feature-movie':
movie_lst.append
else:
media_other_lst.append
return movie_lst, song_lst, media_other_lst
movie_lst.append by itself doesn’t do anything: it refers to the idea of adding to that particular list (which is sometimes very useful!) but it doesn’t use it. You have to pass arguments with () to call a function (even if there are 0 arguments).

python optimization: [a, b, c] > [str(a), str(b), str(c)]

I need to turn a list of various entities into strings. So far I use:
all_ents_dead=[] # converted to strings
for i in all_ents:
all_ents_dead.append(str(i))
Is there an optimized way of doing that?
EDIT: I then need to find which of these contain certain string. So far I have:
matching = [s for s in all_ents_dead if "GROUPS" in s]
Whenever you have a name = [], then name.append() in a loop pattern, consider using a list comprehension. A list comprehension builds a list from a loop, without having to use list.append() lookups and calls, making it faster:
all_ents_dead = [str(i) for i in all_ents]
This directly echoes the code you had, but with the expression inside all_ents_dead.append(...) moved to the front of the for loop.
If you don't actually need a list, but only need to iterate over the str() conversions you should consider lazy conversion options. You can turn the list comprehension in to a generator expression:
all_ents_dead = (str(i) for i in all_ents)
or, when only applying a function, the faster alternative in the map() function:
all_ents_dead = map(str, all_ents) # assuming Python 3
both of which lazily apply str() as you iterate over the resulting object. This helps avoid creating a new list object where you don't actually need one, saving on memory. Do note that a generator expression can be slower however; if performance is at stake consider all options based on input sizes, memory constraints and time trials.
For your specific search example, you could just embed the map() call:
matching = [s for s in map(str, all_ents) if "GROUPS" in s]
which would produce a list of matching strings, without creating an intermediary list of string objects that you then don't use anywhere else.
Use the map() function. This will take your existing list, run a function on each item, and return a new list/iterator (see below) with the result of the function applied on each element.
all_ends_dead = map(str, all_ents)
In Python 3+, map() will return an iterator, while in Python 2 it will return a list. An iterator can have optimisations you desire since it generates the values when demanded, and not all at once (as opposed to a list).

Python list.remove items present in second list

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.

Apply a list of functions to every item in a list?

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.

Enigmatic Naming of Lists in Python

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.

Categories