Related
I want a code in Python lists,to get all the possibility in a given list without using any built in functions.
example = [1,2,3]
def expandList(ex):
rslt = []
for i in range(len(ex)):
for j in range(len(ex)):
rslt.append((ex[i], ex[j]))
return rslt
expandList(example)
Yields:
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
If you are going for each permutation, you would use nested for loops. Example:
permutations = list()
for item in myList:
for item2 in myList:
permutations.append((item, item2))
This code will create a list of permutations.
Having this frustrating issue where i want to pass through the tuples in the following list
through a method on another list of instances of a class that i have created
list_1=[(0, 20), (10, 1), (0, 1), (0, 10), (5, 5), (10, 50)]
instances=[instance[0], instance[1],...instance[n]]
results=[]
pos_list=[]
for i in range(len(list_1)):
a,b=List_1[i]
result=sum(instance.method(a,b) for instance in instances)
results.append(result)
if result>=0:
pos_list.append((a,b))
print(results)
print(pos_list)
the issue is that all instances are taking the same tuple, where as i want the method on the first instance to take the first tuple and so on.
I ultimately want to see it append to the new list (pos_list) if the sum is >0.
Anyone know how i can iterate this properly?
EDIT
It will make it clearer if I print the result of the sum also.
Basically I want the sum to perform as follows:
result = instance[0].method(0,20), instance[1].method(10,1), instance[2].method(0,1), instance[3].method(0,10), instance[4].method(5,5), instance[5].method(10,50)
For info the method is just the +/- product of the two values depending on the attributes of the instance.
So results for above would be:
result = [0*20 - 10*1 - 0*1 + 0*10 - 5*5 + 10*50] = [465]
pos_list=[(0, 20), (10, 1), (0, 1), (0, 10), (5, 5), (10, 50)]
except what is actually doing is using the same tuple for all instances like this:
result = instance[0].method(0,20), instance[1].method(0,20), instance[2].method(0,20), instance[3].method(0,20), instance[4].method(0,20), instance[5].method(0,20)
result = [0*20 - 0*20 - 0*20 + 0*20 - 0*20 + 0*20] = [0]
pos_list=[]
and so on for (10,1) etc.
How do I make it work like the first example?
You can compute your sum using zip to generate all the pairs of correspondent instances and tuples.
result=sum(instance.payout(*t) for instance, t in zip(instances, List_1))
The zip will stop as soon as it reaches the end of the shortest of the two iterators. So if you have 10 instances and 100 tuples, zip will produce only 10 pairs, using the first 10 elements of both lists.
The problem I see in your code is that you are computing this sum for each element of List_1, so if payout produces always the same result with the same inputs (e.g., it has no memory or randomness), the value of result will be the same at each iteration. So, in the end, results will be composed by the same value repeated a number of times equal to the length of List_1, while pos_list will contain all (the sum is greater than 0) or none (the sum is less or equal to zero) of the input tuples.
Instead, it would make sense if items of List_1 were lists or tuples themselves:
List_1 = [
[(0, 1), (2, 3), (4, 5)],
[(6, 7), (8, 9), (10, 11)],
[(12, 13), (14, 15), (16, 17)],
]
So, in this case, supposing that your class for instances is something like this:
class Goofy:
def __init__(self, positive_sum=True):
self.positive_sum = positive_sum
def payout(self, *args):
if self.positive_sum:
return sum(args)
else:
return -1 * sum(args)
instances = [Goofy(i) for i in [True, True, False]]
you can rewrite your code in this way:
results=[]
pos_list=[]
for el in List_1:
result = sum(g.payout(*t) for g, t in zip(instances, el))
results.append(result)
if result >= 0:
pos_list.append(el)
Running the previous code, results will be:
[-3, 9, 21]
while pop_list:
[[(6, 7), (8, 9), (10, 11)], [(12, 13), (14, 15), (16, 17)]]
If you are interested only in pop_list, you can compact your code in only one line:
pop_list = list(filter(lambda el: sum(g.payout(*t) for g, t in zip(instances, el)) > 0, List_1))
many thanks for the above! I have it working now.
Wasn't able to use args given my method had a bit more to it but the use of zip is what made it click
import random
rand=random.choices(list_1, k=len(instances))
results=[]
pos_list=[]
for r in rand:
x,y=r
result=sum(instance.method(x,y) for instance,(x,y) in zip(instances, rand))
results.append(result)
if result>=0:
pos_list.append(rand)
print(results)
print(pos_list)
for list of e.g.
rand=[(20, 5), (0, 2), (0, 100), (2, 50), (5, 10), (50, 100)]
this returns the following
results=[147]
pos_list=[(20, 5), (0, 2), (0, 100), (2, 50), (5, 10), (50, 100)]
so exactly what I wanted. Thanks again!
Convert
((2.0,3.1),(7.0,4.2),(8.9,1.0),(-8.9,7))
to
((2,3),(7,4),(8,1),(-8,7))
It works to convert the tuple to a numpy array, and then apply .astype(int), but is there a more direct way? Also my 'solution' seems too special.
It works to use numpy
import numpy
data = ((2.0,3.1),(7.0,4.2),(8.9,1.0),(-8.9,7))
data1 = numpy.array(data)
data2 = data1.astype(int)
data3 = tuple(tuple(row) for row in data2)
data3 # ((2, 3), (7, 4), (8, 1), (-8, 7))
((2, 3), (7, 4), (8, 1), (-8, 7))
as expected and desired
In [16]: t = ((2.0,3.1),(7.0,4.2),(8.9,1.0),(-8.9,7))
In [17]: tuple(tuple(map(int, tup)) for tup in t)
Out[17]: ((2, 3), (7, 4), (8, 1), (-8, 7))
Using a simple list comprehension:
result = [(int(element[0]), int(element[1])) for element in t]
If you need it back as a tuple, just convert the list into a tuple:
result = tuple([(int(element[0]), int(element[1])) for element in t])
The code prints out 2 and 3 because their product equals the variable num. But what if l=[1,3,4,5,6,7,8,9,10]? No numbers in the list multiplied equal 6,so I'd like to print the two closest ones.
l=[1,2,3,4,5,6,7,8,9,10]
num=6
index=0
while index+1<len(l):
if l[index]*l[index+1]==num:
print(l[index],l[index+1])
index+=1
You can do this with an easy expression with min:
First we use zip to build an iterator for consecutive elements: zip(l, l[1:])
Then we use min with the key being the distance from num:
min(zip(l, l[1:]), key = lambda x: abs(x[0]*x[1]-num))
If l = [1,2,3,4,5,6,7,8,9,10]
Output:
(2, 3)
If l = [1,3,4,5,6,7,8,9,10]
Output:
(1, 3)
If you want to get more outputs consider using sorted in the same manner to get a ranking:
sorted(zip(l, l[1:]), key = lambda x: abs(x[0]*x[1]-num))
If l = [1,3,4,5,6,7,8,9,10]
Output:
[(1, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10)]
If l = [1,2,3,4,5,6,7,8,9,10]
Output:
[(2, 3), (1, 2), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10)]
To find the index for the pair whose product is closest to num you can do:
Code:
min((abs(x*y - num), i) for i, (x, y) in enumerate(zip(l, l[1:])))[1]
Say what?
This uses a generator expression and min() to find the pair whose product is closest to num. In that chain is:
zip(l, l[1:])
which produces a tuple for each neighbor pair. Then enumerate is used to also produce the index. Then the absolute value of the product - num is passed to min()
>>> x=zip(range(1,10),range(2,11))
>>> list(x)
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10)]
>>> list(x)
[]
x is a zip object. It can be listed for only one time: when listed for the second time, the contents disappeared. Why?
zip is an iterator since Python 3. This means, it can only be evaluated once. This decision roots presuambly in the fact that often, one only uses zip to loop over it once (e.g. in for x, y in zip(xs, ys)), so that there is no need to create the whole list of items in memory before iteration is possible.
When the list creation (like in Python 2) is needed, one can explicitly create a list as you did:
list(zip(xs, ys))
In Python 2, similar behaviour can be achieved using:
from itertools import izip
x = izip(xs, ys)
# x will behave as in Python 3