Create new variables inside a loop, that were not previously defined - python

for example,
in this loop:
lst=[1,2,3,4,5,6,7,8,9]
for i in lst:
print i
Instead of just printing i, is there a way to asign i to a new variable each time?
so that I would get something like: item1=1 item2=2 item3=3 and so on.
Or is there a way to create new variables without knowing in advace how many I would need?
For example, a variable for each item in the list lst, or any other list (with any other len()) that the user gives.
for all of you who are wondering. the point of doing this is being able to call the variables later. my code searches for segments within a list that fit to a certein criteria, and I want to be able to reach the segments later, or at least for the user to be able to. I am new to programming, so if you have a better way to do that please tell me.

You want to partition the data according to a certain criteria. Let's say that you have a function figure_out_class that gives you a description for the class that you data falls on. Then you can use a dictionary to do this:
partitions = {}
for i in lst:
key = figure_out_class(i)
if key not in partitions:
partitions[key] = []
partitions[key].append(i)
This "is the key there already?" can be avoided populating the dictionary first using the classes you know you'll need, or using defaultdict:
from collections import defaultdict
partitions = defaultdict(list)
for i in lst:
key = figure_out_class(i)
partitions[key].append(i)
For a practical example, say that you want to classify numbers as odd or even:
def figure_out_class(number):
return ("odd" if number % 2 else "even")
Applying that function to the previous piece of code gives you:
>>> partitions['odd']
[1, 3, 5, 7, 9]
>>> partitions['even']
[2, 4, 6, 8]

Don't do this. You already have the data stored. Instead of doing item1, just do lst[0].
item2 -> lst[1]
item3 -> lst[2]
itemn -> lst[n-1]
Edit 2:
Try this:
>>> from itertools import groupby
>>> def split_condition(x):
return (x == 3)
>>> [list(g) for k, g in groupby([1, 2, 3, 4, 5, 6, 3, 4, 3, 5], split_condition)]
[[1, 2], [3], [4, 5, 6], [3], [4], [3], [5]]

You COULD do:
lst=[1,2,3,4,5,6,7,8,9]
for i in xrange(len(lst)):
exec('item%d=%d' % (i, lst[i]))
which will create variables item0, item1... all having values equal to respective positions in the list.
I don't see the point of all this though :)

Related

How to apply function to list inside list?

I am writing code to sum the second index in a list within a list:
employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
i.e. I want to do 5+3+3= 11
for i in range(len(employees)):
total_importance = sum(input[i][1])
or
total_important = sum(map(list.append, input[i][1]))
print(total_importance)
Now both of the options above for total_importance produce an error- int object is not itterable or other errors. Is there any way I can amend the code above for it to work?
I have another method where I simply append input[i][1] into a new list and then sum from there, and this easily works. But for my knowledge I want to ask if there is any way to amend either of the code above? Thanks
You can use list comprehension to extract the second element and sum on that new list:
sum([l[1] for l in employees])
The above code returns 11 on your employees object.
This also works without creating a new list, by passing a generator to the sum function:
sum(l[1] for l in employees)
You can take advantage of pythons powerful unpack features:
sum(second for first,second,*rest in employees)
This will unpack into three variables, first, second and the rest (in case of uneven lengths).
If you only care to use the second you can use:
sum(second for _,second,*_ in employees)
The line where you wrote total_importance = sum(input[i][1]), inside the sum() you are basically extracting one integer from that list and using sum() on it. This is equivalent to doing sum(2) which would of course cause an error.
Instead, you can do
total_importance = 0
for i in range(len(employees)):
num = employees[i][1]
total_importance += num
You might consider to reduce the list to the desired sum
reduce((lambda x, y: x+y[1]), employees, 0)
EDIT: Please note that input is a built in function in python. In the above mentioned reduce method x represents the "running sum" of summed up elements and y represents an item from the employees list. So x is an int value and y is a list. 0 is the initial value for the calculation:
>>> import functools
>>> employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
>>> functools.reduce((lambda x, y: x+y[1]), employees, 0)
11
So, this is because you are using sum function which works on list. But you are selecting individual element. So you need to do:
total_importance += employees[i][1]
You can make this code more general like even if the second element is list, it will work.
# employees = [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]]
employees = [[1, [5,6], [2, 3]], [2, 3, []], [3, 3, []]]
total_importance=0
for i in range(len(employees)):
if isinstance(employees[i][1], list):
total_importance += sum(employees[i][1])
else:
total_importance += employees[i][1]
print(total_importance)

Leave parts of the instructions blank for python to complete

I'm new to Python so I don't know if this is possible, but my guess is yes. I want to iterate over a list and put items into new lists according to their value. For instance, if item_x == 4, I would want to put it in a list called list_for_4. The same is true for all other items in my list and numbers 0 to 10. So is it possible to generalize a statement in such a way that if item_x == *a certain value*, it will be appended to list_for_*a certain value*?
Thanks!
Maybe use list comprehension with if statement inside?
Like:
list_for_4 = [x for x in my_list if x==4]
And combine it with a dict.
With a simple iteration through the list:
lst_for_1 = []
lst_for_2 = []
lst_for_3 = []
d = {1: lst_for_1, 2: lst_for_2, 3: lst_for_3}
for x in lst:
d[x].append(x)
Or, if you want a condition that is more complicated than just the value of x, define a function:
def f(x):
if some condition...:
return lst_for_1
elif some other condition:
return lst_for_2
else:
return lst_for_3
Then replace d[x].append(x) by f(x).append(x).
If you don't want to do the iteration yourself, you could also use map:
list(map(lambda x: d[x].append(x),lst))
or
list(map(lambda x: f(x).append(x),lst))
The version with map will return an list of Nones that you don't care about. map(...) returns an iterator, and as long as you do not iterate through it (for example, to turn its result into a list), it will not perform the mapping. That's why you need the list(map(...)), it will create a dummy list but append the items of lst to the right lists on the way, which is what you want.
Don't know why you want to do it. But you can do it.
data = [1, 2, 3, 4, 1, 2, 3, 5]
for item in data:
name = f'list_for_{item}'
if name in globals():
globals()[name].append(item)
else:
globals()[name] = [item]
Instead of trying to generate a dynamic variables. A map using a dictionary structure might help you.
For example:
from collections import defaultdict
item_list = [1, 2, 3, 9, 2, 2, 3, 4, 4]
# Use a dictionary which elements are a list by default:
items_map = defaultdict(list)
for i in item_list:
items_map['list_for_{}'.format(i)].append(i)
print(items_map)
# Test the map for elements in the list:
if 'list_for_4' in items_map:
print(items_map['list_for_4'])
else:
print('`list_for_4` not found.')
Alternatively if you only require the number of times an item occurs in the list you could aggregate it using Counter:
from collections import Counter
item_list = [1, 2, 3, 9, 2, 2, 3, 4, 4]
result = Counter(item_list)
print(result)

Converting a list of lists into its sub-lists using a for loop and .format

I would like to apply this idea to separate a list of lists into individually named list. Say L = [[0,1,2],[3,4,5],[6,7,8]] and I want the first list ([0,1,2]) to be separate to give L0 = l[0] (first list within the list is labeled as L0). My ideas is this:
for i in range(11):
'l{}'.format(i) = l[i]
but the error message is this: can't assign to function call. I am hoping to accomplish this ultimately:
for i in range(11):
list( 'l{}'.format(i)) = l[i]
in order to convert the string into a list. Anyone know of an way to make this work or is the idea a bust?
The simplest way to do this is using tuple packing/unpacking
L = [[0,1,2],[3,4,5],[6,7,8]]
L0, L1, L2 = L
print(L0)
print(L1)
print(L2)
result:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
You can create variables dynamically (However I don't think its a good idea). Dynamically creating variables should not be used where a dict can be used instead. If you do not know how to create dynamic variables its probably means you shouldn't. there is more than enough info in the net to look up on a quick google search to know why.
That being said here is a way to do what you want using the dict method.
L = [[0,1,2],[3,4,5],[6,7,8]]
my_dict = {}
for x in range(len(L)):
my_dict[("L%s"%(x))] = L[x]
print (my_dict)
The result would be:
{'L0': [0, 1, 2], 'L1': [3, 4, 5], 'L2': [6, 7, 8]}
Then all you need to do is interact with the dict to get anything you need from those list.
You can use exec to execute a string as if it were Python code:
for i in range(len(L)):
exec('L{} = L[{}]'.format(i, i))
will give you variables L0, L1, L2 in your case.
L = [[0,1,2],[3,4,5],[6,7,8]]
myDict = {}
for index,inner_list in enumerate(L):
key = 'L'+str(index)
myDict[key]=inner_list
print(myDict)
RESULT
{'L0': [0, 1, 2], 'L1': [3, 4, 5], 'L2': [6, 7, 8]}

Is there a more time-wise efficient way to populate a dictionary

I have two lists of integers A and B, same length. List A is an unordered list integers, while list B is an ordered (in ascending order) list of integers with duplicates.
A and B are created such that pairwise no couples A[i],B[i] are identical.
My goal is the create a dictionary with key values taken from A, with values from B that pairwise match with A[i], i.e.,
myDict = {}
for i in A:
myDict[i] = []
for i in range(len(A)):
targetA = A[i]
targetB = B[i]
if targetA in myDict.keys():
myDict[targetA].append(targetB)
For very large datasets, this is taking an extremely long time. Is there another way to come up with the same dictionary in the end, possibly by exploiting the sorted structure of B?
You can use a defaultdict which should be simpler and faster:
from collections import defaultdict
A = [6, 6, 3, 2, 5, 2, 3]
B = [1, 2, 3, 3, 4, 6, 7]
purchase_dict = defaultdict(list)
for key, value in zip(A, B):
purchase_dict[key].append(value)
From the docs:
When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the default_factory function which returns an empty list. The list.append() operation then attaches the value to the new list. When keys are encountered again, the look-up proceeds normally (returning the list for that key) and the list.append() operation adds another value to the list. This technique is simpler and faster than an equivalent technique using dict.setdefault().
What you get:
>>> purchase_dict
defaultdict(<class 'list'>, {2: [3, 6], 3: [3, 7], 5: [4], 6: [1, 2]})
>>> purchase_dict[2]
[3, 6]

Merge two lists that are generated by a python code

I know we can merge two lists by using something like final_list= list1 + list2 but if the lists are generated by a python code and they don't have a variable associated with them like list1 and list2, how can we merge them? Say, my code does something like print output to give:
[1,2,3,4]
[2,0,5,6]
I'd like to merge them so I can get unique values using set(final_list). But how do I get the final_list?
PS- My code can return multiple lists. It is not restricted to two.
def somefunc(param):
#does something
return alist,blist
my_alist,my_blist = somefunc(myparam)
print my_alist, my_blist
#prints both lists.
When you return multiple values from a function they are returned in a tuple. You can easily unpack the tuple
You can either modify the function which is generating output, or the harder way being you manually convert it into a string and then into a set.
list = []
strings_of_list = output.split('\n')
for string in strings_of_list:
values = string[1:-1].split(',')
for val in values:
list+=[int(val)]
set(list)
Assign a variable to a function. Taking the lists the function generated, join them together in another variable. Just make sure that your function returns the generated list, and doesn't just print it out.
# my_list_generator returns two values.
>>> a, b = my_list_generator()
>>> a
[1, 2, 3, 4]
>>> b
[2, 0, 5, 6]
>>> final_list = a + b
>>> final_list
[1, 2, 3, 4, 2, 0, 5, 6]
Cross all that out! Now that I know the function can return multiple objects, let do this (with a little list comprehension):
lists = [i for i in my_list_generator()]
# lists might look like [[1, 2, 3, 4], [2, 0, 5, 6]]
# And now use a for loop to get each value
final_list = []
for sublist in lists:
final_list.extend(sublist)
# final_list will look like [1,2,3,4,2,0,5,6]
Also, if you don't want duplicates, just do one more thing:
real_final_list = [i for i in final_list if i not in real_final_list]
If I understand correctly:
You have a function (let's call it listGen() for now) which returns some number of lists. Now, you want to put these list together into one big list, final_list.
You could do the following:
# listGen defined earlier
final_list = []
for i in listGen():
final_list += i
unique_values = set(final_list) # or whatever you wanted to do with it
Since listGen returns a tuple, we can loop over its contents, those being the lists you want to append to each other.

Categories

Resources