Reputation: 7633
my_list = ['aa', 'aab', 'aaa', 'deff', 'abcde']
my_list is sorted by element length. What I want to do:
for each element from left to right, if an element is part of another element, then remove the shorter element. For example, since 'aa' is part of 'aab', I want to remove 'aa'.
length = len(my_list)
for i in range(0, length):
v = my_list[i]
j = i+1
if j<length:
if v in my_list[j]:
my_list.pop(i)
This loop changed the original list so it breaks.
This version seem working:
length = len(my_list)
new_list = my_list.copy()
for i in range(0, length):
v = my_list[i]
for j in range(i+1, length):
if v in my_list[j]:
new_list.pop(i)
Upvotes: 2
Views: 597
Reputation: 39
my_list = ['aa', 'aab', 'aaa', 'deff', 'abcde']
list_str = str(my_list) # "['aa', 'aab', 'aaa', 'deff', 'abcde']"
new_list = my_list.copy()
next_ptr = 1 # for the beginning "["
for i in range(len(my_list)-1):
next_ptr += 4 + len(my_list[i]) # 4 is for two single quotation('), one comma(,) and one space
if my_list[i] in list_str[next_ptr:]:
new_list.pop(i)
my_list = new_list
Upvotes: 0
Reputation: 13079
You should not modify a list that you are iterating over, which you are effectively doing here. So you would create a new list my_list_out = my_list[:]
and modify that instead of inside the loop.
Some other bits of unsolicited advice about your code (other than suggesting any clever one-liners to solve this):
length = len(my_list)
for i in range(0, length):
v = my_list[i]
j = i+1
if j<length:
if v in my_list[j]:
my_list.pop(i)
the indentation on the for
statement needs fixing
with the enumerate
function, you can replace this sort of construct:
for i in range(0, length):
v = my_list[i]
with this:
for i, v in enumerate(my_list[:length]):
or in this case, because you set length = len(my_list)
, just:
for i, v in enumerate(my_list):`
if j<length
testPutting these together, plus also the fact that (as discussed in comments below) the requirement is to pop the element where the string is part of any later element and not only the immediately adjacent one, gives:
my_list = ['aa', 'aab', 'aaa', 'deff', 'abcde']
my_list_out = my_list[:]
length = len(my_list)
for i, v in enumerate(my_list[ : length-1]):
for v2 in my_list[i+1 :]:
if v in v2:
my_list_out.pop(i)
break
my_list = my_list_out
print(my_list)
In this case, in the inner loop the index is not required, so the loop is simply over the values (for v2 in ...
).
Running this gives:
$ python3 test.py
['aab', 'aaa', 'deff', 'abcde']
Upvotes: 2
Reputation: 30971
It is easier when you process the input list in the reversed order and the reverse the result.
Use the following code (printouts for demonstration only):
out = []
for it in reversed(my_list):
if any(it in s for s in out):
print(f'{it} - drop')
else:
out.append(it)
print(f'{it} - keep')
out = list(reversed(out))
print(out)
Upvotes: 2