-1

How can I remove from a list of list every list in which a '5' is placed before a '3' given an initial list of list like the following one?

[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]

I tried with

for i in list_ck:
   for j in range(0,2):
      if (i[j]=='5' and i[j+1]=='3'):
         list_ck.remove(i)

but it doesn't work

cakeBoy
  • 27
  • 5
  • 2
    Welcome to StackOverflow. See [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). We cannot effectively help you until you post your MRE code and accurately specify the problem. We should be able to paste your posted code into a text file and reproduce the problem you specified. Your given code doesn't run due to undefined variables; "doesn't work" is not a problem specification. – Prune Dec 18 '19 at 21:32
  • What is `ck`? That variable is not defined anywhere in your code. – John Gordon Dec 18 '19 at 21:33
  • I'm sorry I meant list.remove... I corrected the error – cakeBoy Dec 18 '19 at 21:34
  • 2
    Don't redefine `list` in your code. It's a builtin. – Fred Larson Dec 18 '19 at 21:35
  • 3
    I think you're guilty of DWI - Deleting While Iterating. See https://stackoverflow.com/q/1207406/10077 – Fred Larson Dec 18 '19 at 21:36
  • You don't want to modify the list while iterating over it. That leads to nasty behaviours. Instead, create a new list while iterating the original – Tomerikoo Dec 18 '19 at 21:38

3 Answers3

2

It's easier to test whether a 5 occurs before a 3 if they are strings, rather than tuples; so we can use ''.join to convert them to strings.

>>> data = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
>>> [r for r in data if '53' not in ''.join(r)]
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]

This assumes you only want to test for a 5 immediately before a 3, and won't work for more general cases where the strings in the tuple could e.g. be '53' themselves. But it's sufficient for your example.

A more general solution is to use a regex, and join on a character like , which none of the strings will contain:

>>> data = [('5', '3', '1'), ('53', '1', '1'), ('5', '1', '3')]
>>> import re
>>> pattern = re.compile('(^|,)5,(.*,)*3(,|$)')
>>> [r for r in data if not pattern.search(','.join(r))]
[('53', '1', '1')]

Here the pattern (^|,)5,(.+,)*3(,|$) matches a 5 either at the start or after a ,, followed by a comma, followed by any number of things ending with commas, followed by a 3 which is either before a comma or the end of the string.

kaya3
  • 47,440
  • 4
  • 68
  • 97
1

You could use a conditional list comprehension:

# List of Tuples (lot).
list_of_tups = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]

>>> [tup for tup in list_of_tups 
     if not any((a == '5' and b == '3') for a, b in zip(tup, tup[1:]))]
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]

To modify the list inplace rather than create a new list, create an index of items that need to be removed and then pop them off in reverse order.

idx = [n for n, tup in enumerate(list_of_tups) 
       if any((a == '5' and b == '3') for a, b in zip(tup, tup[1:]))]
for i in reversed(idx):
    list_of_tups.pop(i)

>>> list_of_tups
[('3', '3', '3'), ('3', '3', '5'), ('3', '5', '5'), ('5', '5', '5')]
Alexander
  • 105,104
  • 32
  • 201
  • 196
-1

Try to create another list with the same arguments (dont copy them, create new) and remove() from the second list

tab = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]    
tab2 = [('3', '3', '3'), ('3', '3', '5'), ('3', '5', '3'), ('3', '5', '5'), ('5', '3', '3'), ('5', '3', '5'), ('5', '5', '3'), ('5', '5', '5')]
for i in tab:
    for j in range(0,2):
        if i[j]=='5' and i[j+1]=='3':
            tab2.remove(i)
            break
Boendal
  • 2,496
  • 1
  • 23
  • 36
Kezir
  • 1