Removing elements from a list by indexes

How about:

# remove 'FXW' and '==' and 'HEAT' and 'FXR' and '==' and 'BLAH'

listex = ['15', 'FXX' , '46' , 'FXW' , '==' , 'HEAT', 'FXR' , '==' ,'BLAH' , 'FXR' , '==' ,'BLAH']

countDelimiter = listex.count('==')

while countDelimiter:
    indexDelimiter = listex.index('==')
    listex.remove(listex[indexDelimiter-1])
    listex.remove('==')
    listex.pop(indexDelimiter-1)
    countDelimiter = listex.count('==')
print(listex)

… just an alternative to the for ... if loop posted by @mlgtechuser

The advantage of my method over the for .. if loop is that if the list is …
listex = ['FXW', '==', 'HEAT', '15', 'FXX', '46' , 'FXW' , '==' , 'HEAT', 'FXR' , '==' ,'BLAH' , 'FXR' , '==' ,'BLAH']

… the code still works.

1 Like

True. Ross, this illustrates the complication of iterating through a list as you change the list. The for: loop tries to index through the original loop length. Your code re-evaluates the length of the newly-modified loop each cycle and so does Rob’s.

Rather than a wholesale refactoring (rewriting to do the same process with a different code or structure), a simple adjustment to address this in the for: loop is on the last line below.

listex = ['FXW', '==', 'HEAT', '15', 'FXX', '46' , 'FXS' , '==' , 'HEAT', 'FXQ' , '==' ,'BLAH' , 'FXR' , '==' ,'BLAH']
idx = len(listex)
for i in range(idx):
    idx -= 1
    if listex[idx] == '==':
        del listex[idx-1:idx+2]
        idx -= 1
    if idx==0: break  # stops the loop when the index is at the first list element.
#NOTE: If the first element is `'=='` then this code will remove listex[-1:1], 
#      which is a latent problem that isn't likely to come up since `listex`
#      contains equations.

Re-evaluating the length of the list each cycle is more robust but checking it once is faster. This often the trade-off.

The multiple approaches in this thread also show the beauty of Python. It gives you many, many ways to perform a process and so doesn’t hold you back when you conceive of a method. You can just start coding and have something that works pretty quickly. Because of this, you can prototype in Python and get something working then optimize it for speed either by tightening the execution up in Python or by porting it over to a faster language.

Rob, you may have noticed that you can get away with a single iterated ~.remove() as shown below. The ~.pop() is also a bit incongruous, but that’s more of a style matter.

for i in range(3): listex.remove(listex[indexDelimiter-1])

Some will say that any use of a single line loop or conditional is bad style, but I think that it’s extremely suitable when the single line is about the same length of a typical line. It promotes readability, so conforms to PEP8 and PEP20.

Yeah; it’s a bit of a ‘hack’. I only spend about 15mins on it t.b.h and if I was going to use that kind of thing, I’ll for sure find a cleaner way.

Alternatively one can move .count into while loop condition and save repetition/lines:

while listex.count("=="):
    # do something

Instead of removing/deleting it’s possible to add two appropriate slices of list:

while listex.count("=="):
    i = listex.index("==")
    listex = listex[:i-1] + listex[i+1:]

However… it’s easier to ask for forgivness then permission so little longer version with no repetition could look like:

while True:
    try:
        i = listex.index("==")                 # will raise ValueError if '==' is not present
        listex = listex[:i-1] + listex[i+1:]
    except ValueError:
        break

So, the goal is to have an output of: ['15', 'FXX', '46']
… given an input of:
['FXW', '==', 'HEAT', '15', 'FXX', '46' , 'FXW' , '==' , 'HEAT', 'FXR' , '==' ,'BLAH' , 'FXR' , '==' ,'BLAH']

… that is to say ‘remove any item that is == to any other item, including the == deliminator itself’

Not sure that your routine achieves said goal, does it?
Or maybe what you are saying is that your routine could replace a part of mine?

You are right, code posted contains an error. Fortunately it is just a typo. instead of i+1 there should be i+2 and then expected result should be delivered.

Nice!! Way neater than mine!

Good morning everyone.
Second post, so please forgive me in case I miss something about posting rules.
For the fun, here’s a regex solution which works with the test list the OP provided.
The code is self explenatory, and variables are used to make the code clearer, since the result could be achieved with a one-line instruction.

from re import sub


l = ['15',  'FXX', '46', 'FXW', '==', 'HEAT',  'FXR', '==', 'BLAH', '==']


def remove_groups_from_list(input_list: list, delimiter: str) -> list:

    pattern = f',?[^,]+,{delimiter},[^,]+,?|{delimiter}'
    list_to_string = ','.join(input_list)
    output_list = sub(pattern, '', list_to_string).split(',')

    return output_list


print(remove_groups_from_list(l, '=='))

Happy coding everyone :slight_smile:

Cheers.

1 Like

Neat , much neater than my dubious while loop :slight_smile:

1 Like