Reputation:
I am dealing with some kind of problem and i could not find any solution. My problem is I am controlling a value in a nested list if it is not in another list and deleting it if it is not there but in the not in line it gives me an error like index out of range.
def heroes_updater(men_pref,women):
for i in range(0,len(men_pref)-1):
for j in range(0,len(men_pref[i])-1):
if men_pref[i][j] not in women:
men_pref[i]=men_pref[i][:j]+men_pref[i][j+1:]
example men_pref:
[['Storm', 'Black Widow', 'Scarlet Witch', 'Rouge', 'Mystique', 'Jean Grey', 'Ms. Marvel', 'Gamora', 'Invisible Woman', 'Elektra'], ['Storm', 'Elektra', 'Jean Grey', 'Scarlet Witch', 'Mystique', 'Ms. Marvel', 'Gamora', 'Rouge', 'Black Widow', 'Invisible Woman'], ['Invisible Woman', 'Scarlet Witch', 'Mystique', 'Black Widow', 'Ms. Marvel', 'Elektra', 'Jean Grey', 'Gamora', 'Storm', 'Rouge']]
example women:
['Jean Grey', 'Elektra', 'Mystique', 'Ms. Marvel', 'Rouge']
And the error is :
if men_pref[i][j] not in women:
IndexError: list index out of range
Upvotes: 3
Views: 263
Reputation: 180481
You can use a set with a list comp, you cannot iterate over and mutate a list as each time you remove an element the list gets smaller and your index is based on what the size of the list when you started the range:
men = [['Storm', 'Black Widow', 'Scarlet Witch', 'Rouge', 'Mystique', 'Jean Grey', 'Ms. Marvel', 'Gamora', 'Invisible Woman', 'Elektra'], ['Storm', 'Elektra', 'Jean Grey', 'Scarlet Witch', 'Mystique', 'Ms. Marvel', 'Gamora', 'Rouge', 'Black Widow', 'Invisible Woman'], ['Invisible Woman', 'Scarlet Witch', 'Mystique', 'Black Widow', 'Ms. Marvel', 'Elektra', 'Jean Grey', 'Gamora', 'Storm', 'Rouge']]
wom = {'Jean Grey', 'Elektra', 'Mystique', 'Ms. Marvel', 'Rouge'}
men[:] = [[ele for ele in sub if ele in wom] for sub in men]
print(men)
Or functionally if order is irrelevant:
men = [['Storm', 'Black Widow', 'Scarlet Witch', 'Rouge', 'Mystique', 'Jean Grey', 'Ms. Marvel', 'Gamora', 'Invisible Woman', 'Elektra'], ['Storm', 'Elektra', 'Jean Grey', 'Scarlet Witch', 'Mystique', 'Ms. Marvel', 'Gamora', 'Rouge', 'Black Widow', 'Invisible Woman'], ['Invisible Woman', 'Scarlet Witch', 'Mystique', 'Black Widow', 'Ms. Marvel', 'Elektra', 'Jean Grey', 'Gamora', 'Storm', 'Rouge']]
wom = {'Jean Grey', 'Elektra', 'Mystique', 'Ms. Marvel', 'Rouge'}
men[:] = map(list,map(wom.intersection, men))
print(men)
You could also start from the end of the list, using your range logic but using range(len(sub)-1,-1, -1)
but it is easier to just to use reversed and iterate over the elements themselves:
def heroes_updater(men_pref, women):
for sub in men_pref:
for m in reversed(sub):
if m not in women:
sub.remove(m)
Upvotes: 1
Reputation: 5866
You're editing the list you're reading, you must never do that.
With the line men_pref[i]=men_pref[i][:j]+men_pref[i][j+1:]
you're removing an item from the list men_pref[i]
, but your j
variable goes from 0
to the original lenght of the list, so you'll eventually have an index error when you check for men_pref[i][j]
if j>len(men_pref[i])
EDIT: Of, if you want to edit your current list, then you'll have to read it with a backwards index (you start from the last, if it's not on the list of women, you remove it and then continue with the next item):
def heroes_updater(men_pref,women):
for i in range(len(men_pref)-1, -1,-1):
for j in range(len(men_pref[i])-1, -1, -1):
if men_pref[i][j] not in women:
men_pref[i].pop(j)
# An alternative: del(mem_pref[i][j])
Another way would be to use list comprehension:
def heroes_updater(men_pref,women):
for i in range(len(men_pref)-1, -1,-1):
mem_pref[i] = [_w_ for _w_ in mem_pref[i] if _w_ in women]
There are other options, but I'll leave that to you. That's how you learn.
Upvotes: 1
Reputation: 42778
By removing elements from your list, the list gets shorter j
is larger than the length of the list. To circumvent this problem, just don't alter the lists, but create a new one:
def heroes_updater(men_pref,women):
result = []
for prefs in men_pref:
new_prefs = []
for pref in prefs:
if pref in women:
new_prefs.append(pref)
result.append(new_prefs)
men_pref[:] = result
or better:
def filter_non_heroes(men_pref,women):
return [
[pref for pref in prefs if pref in women]
for prefs in men_pref
]
Upvotes: 1