I have a very specific use-case for creating a list comprehension and I am having a bit of trouble figuring out how to do it. I am sure there must be a method or function that can help me, but I guess I am not aware of it.
Here is the scenario: Following code works as expected and generates all expected variations (8 in total)
List_A = ["apples","oranges"]
List_B = ["meat","chicken"]
flexibility = range(2)
list = []
for a in List_A:
results = [(day, b, a) for day in flexibility for b in List_B]
list.append(results)
print (list)
result
[[(0, 'meat', 'apples'), (0, 'chicken', 'apples'), (1, 'meat', 'apples'), (1, 'chicken', 'apples')],
[(0, 'meat', 'oranges'), (0, 'chicken', 'oranges'), (1, 'meat', 'oranges'), (1, 'chicken', 'oranges')]]
Here is the complication. Let's assume I have a rate limit of 5 calls per second, and the list above creates 8 elements, hence I would go above the rate limit. The way I thought I could overcome this, was to create another variable to pass on to the function that will use a different accounts to make my api request. In theory, each account would make only 5 requests. Thus in my example above, the first 5 elements of the list would have account 0 and the rest 3 would use account 1. I tried using list comprehension to achieve this, but the result is not what I expected:
no = [0,1,2]
List_A = ["apples","oranges"]
List_B = ["meat","chicken"]
flexibility = range(2)
list = []
for a in List_A:
results = [(day, b, a,n) for day in flexibility for b in List_B for n in no]
list.append(results)
print (list)
results
[[(0, 'meat', 'apples', 0), (0, 'meat', 'apples', 1), (0, 'meat', 'apples', 2), (0, 'chicken', 'apples', 0), (0, 'chicken', 'apples', 1), (0, 'chicken', 'apples', 2), (1, 'meat', 'apples', 0), (1, 'meat', 'apples', 1), (1, 'meat', 'apples', 2), (1, 'chicken', 'apples', 0), (1, 'chicken', 'apples', 1), (1, 'chicken', 'apples', 2)],
[(0, 'meat', 'oranges', 0), (0, 'meat', 'oranges', 1), (0, 'meat', 'oranges', 2), (0, 'chicken', 'oranges', 0), (0, 'chicken', 'oranges', 1), (0, 'chicken', 'oranges', 2), (1, 'meat', 'oranges', 0), (1, 'meat', 'oranges', 1), (1, 'meat', 'oranges', 2), (1, 'chicken', 'oranges', 0), (1, 'chicken', 'oranges', 1), (1, 'chicken', 'oranges', 2)]]
I get many more elements in my list than what I want. I still want the original 8 but the first five would use account 0 and the last 3 account 1.
The goal is to get this list:
[(0, 'apples', 'meat',0),
(0, 'apples', 'chicken',0),
(0, 'oranges', 'meat',0),
(0, 'oranges', 'chicken',0),
(1, 'apples', 'meat',0),
(1, 'apples', 'chicken',1),
(1, 'oranges', 'meat',1),
(1, 'oranges', 'chicken',1)]
How can I achieve this? thanks
A concise way to do this combines itertools.product
to give the combinations, with enumerate
to give you a running counter. You can floor-divide that counter by 5 to give your "account number":
import itertools
List_A = ["apples", "oranges"]
List_B = ["meat", "chicken"]
flexibility = range(2)
rate_limit = 5
res = [(n, a, b, i // rate_limit)
for i, (n, a, b) in enumerate(itertools.product(flexibility, List_A, List_B))]
print(res)
which gives the output list you're looking for:
[(0, 'apples', 'meat', 0), (0, 'apples', 'chicken', 0), (0, 'oranges', 'meat', 0), (0, 'oranges', 'chicken', 0), (1, 'apples', 'meat', 0), (1, 'apples', 'chicken', 1), (1, 'oranges', 'meat', 1), (1, 'oranges', 'chicken', 1)]