Python change string into variable name - python

So I have a list of strings MyList=['ID_0','ID_1','ID_2',.....] from which I used an exec function to create a empty list with elements as names i.e. each I have empty lists ID_0=[] and so on.
I now want to create a for loop where I take each list by name and append elements to it like
for i in range(len(MyList)):
*magic*
ID_0.append(i)
where with each loop it uses to next list i.e. ID_1,ID_2.... and so on
I wanted to take each string in MyList and change it into a variable name. Like take 'ID_0' and change it into say ID_0 (which is a empty list as defined earlier) and then make a list BigList=[ID_0,ID_1,ID_2,.....] so that I can just call each list from BgList in my for loop but I dont know how

A safer way instead of using exec might be to construct a dictionary, so you can safely refer to each list by its ID:
MyList=['ID_0','ID_1','ID_2']
lists = {}
for i, list_id in enumerate(MyList):
lists[list_id] = [i]
Note that using enumerate is more pythonic than range(len(MyList)). It returns tuples of (index, item).
Alternatively, you could also use defaultdict, which constructs a new item in the dictionary the first time it is referenced:
from collections import defaultdict
lists = defaultdict(list)
for i, list_id in enumerate(MyList):
lists[list_id].append(i)

Related

How to convert this loop into list comprehension?

Hello i would like make list comprehension for two loops and return value from first loop. I have example:
rows = []
for row in value:
for pattern, sub_pattern in zip(pattern_tag, sub_pattern_list):
row = re.sub(pattern, sub_pattern, row)
rows.append(row)
how do I make a list, through list Comprehension, so that it gives the same result
This is probably not what you were looking for, but it's still a one-liner that makes use of the functools.reduce function:
from functools import reduce
from re import sub
rows = [
reduce(
lambda prev, curr: sub(*curr, prev),
zip(pattern_tag, sub_pattern_list),
row,
)
for row in value
]
To elaborate on Ricardo Bucco's answer and luk2302's comment.
List comprehensions create lists from other lists/iterables. Every item of "source" iterable either produces one item of resulting list or is skipped (if list comprehension has if clause). The order is preserved.
So your outer for loop can be converted to a list comprehension, since it constructs a list of replacements from a list of strings (presumably).
rows = [re.sub(..., ..., row) for row in value]
Inner for loop creates no list, and instead does a lot of subsequent replacements on a string, so it's not something that could be done using list comprehensions (hence _Riccardo_s' idea to use reduce()).

Sorting out unique elements from a list to a set

I was writing a function to save unique values returned by a list "list_accepted_car" to a set "unique_accepted_ant". list_car_id is list with the value ['12','18','3','7']. When i run the code i am getting error , "unhashable list ". Can anyone suggest me what is the error?
list_accepted_car = [] #set to store the value list_accepted_car
unique_accepted_car = set() #set to store the value unique_accepted_car
num_accepted = 2 #predifined value for the number of cars allowed to enter
def DoIOpenTheDoor(list_car_id): #list_ant_id is a list of cars allowed to enter
if len(list_accepted_car) < num_accepted:
if len(list_car_id) > 0:
list_accepted_car.append(list_car_id[0:min(len(list_car_id),num_accepted-len(list_accepted_car))])
unique_accepted_list = set(list_accepted_car)
print unique_accepted_list
return list_accepted_car
Under the assumption that list_car_id looks like: [1,2,3,4,5].
You add in list_accepted_car a sublist of list_car_id, so list_accepted_car will look like [[1,2]] i.e. a list of a list.
Then you should change
unique_accepted_list = set(list_accepted_car)
to
unique_accepted_list = set([x for y in list_accepted_car for x in y])
which will extract each element of the sublist and provide a flatten list. (There exists other options to flatten a list of list)
You are saving a list of lists, which can't be converted to a set. You have to flatten it first. There are many examples of how to do it (I'll supply one using itertools.chain which I prefer to python's nested comprehension).
Also, as a side note, I'd make this line more readable by separating to several lines:
list_accepted_car.append(list_car_id[0:min(len(list_car_id),num_accepted-len(list_accepted_car))])
You can do:
from itertools import chain
# code ...
unique_accepted_list = set(chain.from_iterable(list_accepted_car))
The best option would be to not use a list at all here, and use a set from the start.
Lists are not hashable objects, and only hashable objects can be members of sets. So, you can't have a set of lists. This instruction:
list_accepted_car.append(list_car_id[0:min(len(list_car_id),num_accepted-len(list_accepted_car))])
appends a slice of list_car_id to list_accepted_car, and a slice of a list is a list. So in effect list_accepted_car becomes a list of lists, and that's why converting it to a set:
unique_accepted_list = set(list_accepted_car)
fails. Maybe what you wanted is extend rather than append? I can't say, because I don't know what you wanted to achieve.

Convert a list comprehension loop into a regular for loop without creating an infinite loop

I am trying to convert this list comprehension:
cfg = []
...
cfg = [conf + function1(s) for s in cfg]
To a regular multiline for, because it is necessary to include more things into it:
cfg = []
...
for s in cfg:
cfg.append(conf + function1(s))
But in the second case, an infinite loop is created.
What is the equivalence for the list comprehension to a normal for loop?
You can do two things:
create a copy of cfg beforehand:
for s in cfg[:]:
or append to a new list and replace the old:
new_cfg = []
for s in cfg:
new_cfg.append(...)
cfg = new_cfg
The second option is the closest equivalent to the list comprehension, as it also creates a new list first before rebinding. The second option replaces the old cfg list values.
Your full for loop, however, is equivalent to the first option, since that option preserves the old values of cfg, appending new values. Your list comprehension never did this.

List Comprehension of Lists Nested in Dictionaries

I have a dictionary where each value is a list, like so:
dictA = {1:['a','b','c'],2:['d','e']}
Unfortunately, I cannot change this structure to get around my problem
I want to gather all of the entries of the lists into one single list, as follows:
['a','b','c','d','e']
Additionally, I want to do this only once within an if-block. Since I only want to do it once, I do not want to store it to an intermediate variable, so naturally, a list comprehension is the way to go. But how? My first guess,
[dictA[key] for key in dictA.keys()]
yields,
[['a','b','c'],['d','e']]
which does not work because
'a' in [['a','b','c'],['d','e']]
yields False. Everything else I've tried has used some sort of illegal syntax.
How might I perform such a comprehension?
Loop over the returned list too (looping directly over a dictionary gives you keys as well):
[value for key in dictA for value in dictA[key]]
or more directly using dictA.itervalues():
[value for lst in dictA.itervalues() for value in lst]
List comprehensions let you nest loops; read the above loops as if they are nested in the same order:
for lst in dictA.itervalues():
for value in lst:
# append value to the output list
Or use itertools.chain.from_iterable():
from itertools import chain
list(chain.from_iterable(dictA.itervalues()))
The latter takes a sequence of sequences and lets you loop over them as if they were one big list. dictA.itervalues() gives you a sequence of lists, and chain() puts them together for list() to iterate over and build one big list out of them.
If all you are doing is testing for membership among all the values, then what you really want is to a simple way to loop over all the values, and testing your value against each until you find a match. The any() function together with a suitable generator expression does just that:
any('a' in lst for lst in dictA.itervalues())
This will return True as soon as any value in dictA has 'a' listed, and stop looping over .itervalues() early.
If you're actually checking for membership (your a in... example), you could rewrite it as:
if any('a' in val for val in dictA.itervalues()):
# do something
This saves having to flatten the list if that's not actually required.
In this particular case, you can just use a nested comprehension:
[value for key in dictA.keys() for value in dictA[key]]
But in general, if you've already figured out how to turn something into a nested list, you can flatten any nested iterable with chain.from_iterable:
itertools.chain.from_iterable(dictA[key] for key in dictA.keys())
This returns an iterator, not a list; if you need a list, just do it explicitly:
list(itertools.chain.from_iterable(dictA[key] for key in dictA.keys()))
As a side note, for key in dictA.keys() does the same thing as for key in dictA, except that in older versions of Python, it will waste time and memory making an extra list of the keys. As the documentation says, iter on a dict is the same as iterkeys.
So, in all of the versions above, it's better to just use in dictA instead.
In simple code just for understanding this might be helpful
ListA=[]
dictA = {1:['a','b','c'],2:['d','e']}
for keys in dictA:
for values in dictA[keys]:
ListA.append(values)
You can do some like ..
output_list = []
[ output_list.extend(x) for x in {1:['a','b','c'],2:['d','e']}.values()]
output_list will be ['a', 'b', 'c', 'd', 'e']

Modify the list that is being iterated in python

I need to update a list while it is being iterated over.
Basically, i have a list of tuples called some_list Each tuple contains a bunch of strings, such as name and path. What I want to do is go over every tuple, look at the name, then find all the tuples that contain the string with an identical path and delete them from the list.
The order does not matter, I merely wish to go over the whole list, but whenever I encounter a tuple with a certain path, all tuples (including oneself) should be removed from the list. I can easily construct such a list and assign it to some_list_updated, but the problem seems to be that the original list does not update...
The code has more or less the following structure:
for tup in some_list[:]:
...
...somecode...
...
some_list = some_list_updated
It seems that the list does update appropriately when I print it out, but python keeps iterating over the old list, it seems. What is the appropriate way to go about it - if there is one? Thanks a lot!
You want to count the paths using a dictionary, then use only those that have a count of 1, then loop using a list comprehension to do the final filter. Using a collections.Counter() object makes the counting part easy:
from collections import Counter
counts = Counter(tup[index_of_path] for tup in some_list)
some_list = [tup for tup in some_list if counts[tup[index_of_path]] == 1]

Categories