I have a list of tuples from this:
from itertools import product
l1 = list((product((0,1), repeat = n)))
For n=4, output is the following:
[(0, 0, 0, 0),
(0, 0, 0, 1),
(0, 0, 1, 0),
(0, 0, 1, 1),
(0, 1, 0, 0),
(0, 1, 0, 1),
(0, 1, 1, 0),
(0, 1, 1, 1),
(1, 0, 0, 0),
(1, 0, 0, 1),
(1, 0, 1, 0),
(1, 0, 1, 1),
(1, 1, 0, 0),
(1, 1, 0, 1),
(1, 1, 1, 0),
(1, 1, 1, 1)]
I want to remove the tuples where at least two "1" are next to each other, for example the (0,1,1,0)
.
I tried this:
for i in l1:
for j in i:
if j==1 and j+1 == 1:
l1.remove(i)
I guess this is not working because it takes j+1 as the actual number + 1, like if j=1 it takes as 2 and etc.
What should I do differently?
You could build neighbor pairs with zip(i, i[1:])
and check whether they contain (1, 1)
:
>>> [i for i in l1 if (1, 1) not in zip(i, i[1:])]
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0),
(0, 1, 0, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0)]
Your approach makes logical sense but unfortunately won't work in Python (or most other languages), and the implementation isn't correct because j==1 and j+1 == 1
is never true; if j
is equal to 1 then j+1
is equal to 2, period. But the bigger issue is that you are trying to remove things from a list while iterating over it, which is a no-no .
First let's solve the problem of how to check if two 1s are next to each other. Instead of looking at j
and j+1
, we need to look at t[j]
and t[j+1]
where t
is one of the tuples. Also, j
needs to iterate up to the length minus 1, otherwise t[j+1]
will give an IndexError
at the end of the tuple. The any
function is a convenient way to do this:
any(t[j] == t[j+1] == 1 for j in range(n - 1))
Note that t[j] == t[j+1] == 1
works in Python because of chained comparisons .
Now let's solve the problem of how to remove such elements from the list. It is much more convenient to simply build a new list with just the elements you want, rather than remove the ones you don't want. A list comprehension is a convenient way to do this:
result = [
t for t in product((0, 1), repeat=n)
if not any(t[j] == t[j+1] == 1 for j in range(n - 1))
]
Result:
[(0, 0, 0, 0),
(0, 0, 0, 1),
(0, 0, 1, 0),
(0, 1, 0, 0),
(0, 1, 0, 1),
(1, 0, 0, 0),
(1, 0, 0, 1),
(1, 0, 1, 0)]
All of that said, for larger n it would be more efficient to use an algorithm which generates only the elements you do want, rather than loop over the whole cartesian product (of size 2 n ) and reject the ones you don't want.
This ought to do the trick:
>>> n = 4
>>> from itertools import product
>>> l1 = list((product((0,1), repeat = n)))
>>> l1
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 0, 1, 1), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 1, 0), (0, 1, 1, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0), (1, 0, 1, 1), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 1, 0), (1, 1, 1, 1)]
>>> [t for t in l1 if not any(t[i] == 1 and t[i+1] == 1 for i in range(n-1))]
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, 0), (0, 1, 0, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0)]
The not any(t[i] == 1 and t[i+1] == 1 for i in range(n-1))
condition basically checks whether consecutive elements are equal to one. Note the range(n-1)
index iterator - we don't want to check the n th element against the n +1th element since there isn't a fifth element in any of the tuples above.
Timing
Note my function is about twice as slow as that of Heap Overflow .
>>> from time import time as t
>>> def f1():
... t0 = t()
... result = [i for i in l1 if (1, 1) not in zip(i, i[1:])]
... t1 = t()
... print(t1-t0)
...
>>> def f2():
... t0 = t()
... result = [t for t in l1 if not any(t[i] == 1 and t[i+1] == 1 for i in range(n-1))]
... t1 = t()
... print(t1-t0)
...
>>> l1 = list((product((0,1), repeat = n))) * 1000000
>>> len(l1)
16000000
>>> f1()
8.146391868591309
>>> f2()
18.645386934280396
Adding a less "pythonic" but more readable example for consideration:
def filter_helper(t):
for i, val in enumerate(t):
if i != 0 and (t[i-1]) == val and val == 1:
return False
return True
print(list(filter(filter_helper, a)))
Where a
is the original list of tuples.
Can be done with forloop and use of python's any() method too
for x in l1:
if any([(x[i]==x[i+1]==1) for i in x]) == True:
l1.remove(x)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.