Buster3650
Buster3650

Reputation: 478

How to count in for loop with dynamic if statements in python

I have a total number of tasks at 6716, and a dictionary consisting of a token as key and a length as item. What i need to do is to count up to the first length in the dictionary. In other words, if I have a total task of 6716 and dictionary = {'tok1':5121}, then I need to do something when iterating up to 5121. If the dictionary looks like: dictionary = {'tok1':5121, 'tok2':802, 'tok3':793}, then it would need to do something when iterating the first 5121, then it should do something else the next 802, and eventually do something else when iterating the next 793, which would all sum up to iterating to 6716.

I imagined that it would look something like the following:

num_tasks = 6716
dict = {'tok1':5121, 'tok2':802, 'tok3':793}

for i in range(num_tasks):
   if i <= dict['tok1']
       do something...
   elif i > dict['tok1'] and i <= dict['tok1'] + dict['tok2']
       do something...
   elif i > dict['tok1'] + dict['tok2']
       do something...

Although this in theory should work, it is not the most optimal way of looping, since we might have 1000's of tokens one day, and therefore I would need to add 1000's if statements, which isn't very scalable. Therefore, I need help to find a more dynamic way of looping like this.

CODE

    list = ['tok1', 'tok2', 'tok3']
    dict = {'tok1':5121, 'tok2':802, 'tok3':793}
    nexts = iter(customerNumbers)
    try:
        for i in range(n_tasks): # n_tasks = 6716

            single = file['xxx'][i]
            test = file['xxx'][i]['number']

            if test in custom:
                self.params["skippages"] += 1

            if test in customerNumbers: # customerNumbers is a list containing numbers of customers
                url = self.url + f'customers/{next(nexts)}' 
                 
                # Here i need to say that for the first 5121 in num_tasks, change token to the first item in the list containing tokens, then for the next 802 in num_tasks change token to 'tok2' from the list containing tokens etc.
                # For example: if i <= 5121 then token = list[0], if i > 5121 and i < 5121+802 then change token = list[1] etc.
                headers = {'X-AppSecretToken': self.secret_token, 'X-AgreementGrantToken': {token}, 'Content-Type': "application/json"}
                pool.apply_async(request_put, args=(url, headers, self.params, json.dumps(single)))

    except StopIteration:
        pass

    # wait for all tasks to complete:
    pool.close()
    pool.join()

def request_put(url, headers, params, single):
    return requests.put(url=url, headers=headers, params=params, data=single)

Upvotes: 1

Views: 589

Answers (5)

Giulio Mattolin
Giulio Mattolin

Reputation: 650

Assuming you have to work with the numbers of the tasks and assigning them one of the tokens based on the interval they are in, this could be an implementation:

tasks = 10
d = {'tok1':3, 'tok2':5, 'tok3':1, 'tok4':1}

keys = list(d.keys())

counter = 0

for i in range(len(d)):

    if i == 0:
        for j in range(counter, d[keys[i]]):
            print('task {} using {}'.format(counter, keys[i])) # or do something ...
            counter += 1

    elif i == (len(d)-1):
        for j in range(counter, counter+d[keys[i]]):
            print('task {} using {}'.format(counter, keys[i])) # or do something ...
            counter += 1
        
    else:
        for j in range(counter, counter+d[keys[i]]):
            print('task {} using {}'.format(counter, keys[i])) # or do something ...
            counter += 1

Upvotes: 0

Elia
Elia

Reputation: 822

This assumes keys ids are sequential. You could change the current token based on each token's range.

dict = {'tok1':(5121, 'token-01'), 'tok2':(802, 'token-02')}

current_id = 1
current_token = dict[f'tok{current_id}'][1]
done_tasks = 0

for i in range(tasks):
   if i >= dict[f'tok{current_id}'] + done_tasks:
       done_tasks += dict[f'tok{current_id}'][0]
       current_id += 1
       current_token = dict[f'tok{current_id}'][1] 
   do_something_with_current_token(current_token)

Upvotes: 0

CutePoison
CutePoison

Reputation: 5355

I would advice to create your intervals as a list, write a function for each "interval" and then chose the function, based on what interval your i is in.

First, create intervals

import numpy as np
d = {'tok1':5121, 'tok2':802, 'tok3':793} #Dont use "dict" as variable
interval = list(d.values()) # [5121,802,793]

interval_higher = np.cumsum(interval) # array([5121, 5923, 6716], dtype=int32)
interval_lower = [0]
interval_lower.extend(interval_higher[:-1]) 
interval_lower = np.array(interval_lower) # np.array([0, 5121, 5923])

now we define a list of functions for each interval


def func1():
    pass
def func2():
    pass
def func3():
    pass

func_list = [func1,  #Define your functions for each interval
    func2,
    func3,
]
func_list = np.array(func_list)

atlast, loop, get the index of where your i is in, and get the apropiate function

for i in range(tasks):
    idx_high = i<=interval_higher
    idx_low = i>interval_lower

    func_idx = idx_high & idx_low #Get the index of function e.g [False,True,False] --> second interval (tok2)

    func = func_list[func_idx] #Get the function for tok2
    func() #Run it

The full script

import numpy as np
d = {'tok1':5121, 'tok2':802, 'tok3':793} #Dont use "dict" as variable
interval = list(d.values()) # [5121,802,793]

interval_higher = np.cumsum(interval) # array([5121, 5923, 6716], dtype=int32)
interval_lower = [0]
interval_lower.extend(interval_higher[:-1]) # [0, 5121, 5923]
interval_lower = np.array(interval_lower)


func_list = [func1,  #Define your functions for each interval
    func2,
    func3,
]
func_list = np.array(func_list)

tasks = 6716
for i in range(tasks):
    idx_high = i<=interval_higher
    idx_low = i>interval_lower

    func_idx = idx_high & idx_low #Get the index of function e.g [False,True,False] --> second interval (tok2)

    func = func_list[func_idx] #Get the function for tok2
    func() #Run the function

Upvotes: 0

Panda
Panda

Reputation: 131

you still have the problem of multiple if's if you are going to do something different to each range,

but this will automatically give you each range:

dictt = {'tok1':5121, 'tok2':802, 'tok3':793}

lisdict = list(dictt)
start = 0
end = 0
for i in range(len(lisdict)):
    if i != 0:
        # if =
        start = dictt[lisdict[i-1]] + start
        end = dictt[lisdict[i]] + start
        print (f"from: {start}")
        print (f"to: {end}")
        # if i == 1:
        #     "do something"
        # if i == 2:
        #     "do something"
        # .
        # .
        # .

Upvotes: 0

Anis R.
Anis R.

Reputation: 6912

In case your "do something" are similar-ish across tokens, then a possibility is the following:

for k, v in dic.items():
    for i in range(v):
        # "do something"
        # where k is the token and v is the length

Upvotes: 2

Related Questions