Reputation: 1132
In my project I have a list like this one:
varlist = [['Variables', ''], ['bs_${FORM_URL}', 'SC'], ['${FORM_URL}', 'http://www.example.com'], ['bs_${NUM_RAND}', 'RN'], ['${NUM_RAND}', '0-200'], ['bs_${TEXT}', 'SC'], ['${TEXT}', 'mytest']]
I have to check if there is a data with RN
value and, if I found this, change next nested list value with a random value based on next list value.
In my example there is a list with RN
(['bs_${NUM_RAND}', 'RN']), well, I have to remove it and change next list value (['${NUM_RAND}', '0-200']) creating an int random between 0 and 200.
I try like this:
p_oper = 'SC'
for li in varlist:
if li[0][0:3] == 'bs_':
p_oper = li[1]
varlist.remove(li)
else:
if p_oper == 'RN':
num1 = int(li[1].split('-')[0].strip())
num2 = int(li[1].split('-')[1].strip())
li[1] = str(int(random.randint(num1, num2)))
At the end of my function the resulting list should be like this one:
[['Variables', ''], ['${FORM_URL}', 'http://www.example.com'], ['${NUM_RAND}', '42'], ['${TEXT}', 'mytext']]
but this does not work. Anyone has any idea about how I can manipulate my list of lists in that fashion?
Upvotes: 0
Views: 85
Reputation: 13858
Instead of removing the items you might opt to strip out the "bs" sublists and create a new one instead:
varlist[0]] + [[v[0], str(random.randint(*map(int, v[1].split('-'))))] if bs[1] == 'RN' else v for bs, v in zip(varlist[1::2], varlist[2::2])]
# Result:
[['Variables', ''], ['${FORM_URL}', 'http://www.example.com'], ['${NUM_RAND}', '4'], ['${TEXT}', 'mytest']]
This one liner can basically be rewritten to this:
l = [varlist[0]]
for bs, v in zip(varlist[1::2], varlist[2::2]):
if bs[1] == 'RN':
n, m = map(int, v[1].split('-'))
l.append([v[0], str(random.randint(n, m))])
else:
l.append(v)
The zip
function allows you to cross reference slices of the original varlist
while effectively removing the "bs" sublists at the same time.
Upvotes: 2
Reputation: 897
This is happening because your indexes change once you delete items in your list of lists. An easy fix would be to maintain the state of the original list and make your modifications to a copy of that list like so:
import random
p_oper = 'SC'
new_varlist = varlist[:] # Making a copy of the original list
for li in varlist:
if li[0][0:3] == 'bs_':
p_oper = li[1]
new_varlist.remove(li) # Removing the item in the new list only
else:
if p_oper == 'RN':
num1 = int(li[1].split('-')[0])
num2 = int(li[1].split('-')[1])
li[1] = str(int(random.randint(num1, num2)))
Now you have a working code and access to both lists that print exactly what you are looking for:
>>> print(varlist)
[['Variables', ''], ['bs_${FORM_URL}', 'SC'], ['${FORM_URL}', 'http://www.example.com'], ['bs_${NUM_RAND}', 'RN'], ['${NUM_RAND}', '90'], ['bs_${TEXT}', 'SC'], ['${TEXT}', 'mytest']]
>>> print(new_varlist)
[['Variables', ''], ['${FORM_URL}', 'http://www.example.com'], ['${NUM_RAND}', '90'], ['${TEXT}', 'mytest']]
If you want to keep your original list intact without modifying the list ['${NUM_RAND}', '0-200']
, you could also make a deep copy. This is also easily done if you need this functionality:
from copy import deepcopy
p_oper = 'SC'
original_varlist = deepcopy(varlist)
# ...
Upvotes: 2
Reputation: 3988
Assuming that there is always two items in your list's sublists; it can be done this way:
import random
varlist = [['Variables', ''], ['bs_${FORM_URL}', 'SC'], ['${FORM_URL}', 'http://www.example.com'], ['bs_${NUM_RAND}', 'RN'], ['${NUM_RAND}', '0-200'], ['bs_${TEXT}', 'SC'], ['${TEXT}', 'mytest']]
for i,j in enumerate(varlist):
if 'RN' in j:
varlist.remove(varlist[i])
varlist[i][1] = random.randint(0, 200)
print(varlist)
Output: [['Variables', ''], ['bs_${FORM_URL}', 'SC'], ['${FORM_URL}', 'http://www.example.com'], ['${NUM_RAND}', 147], ['bs_${TEXT}', 'SC'], ['${TEXT}', 'mytest']]
Upvotes: 1