itertools py3.4 - filter list using not equal - fails as bool
Peter Otten
__peter__ at web.de
Wed May 13 03:40:05 EDT 2015
Sayth Renshaw wrote:
> why can't I filter a list based on an itertools condition using dropwhile?
>
> This is the docs and the example.
> https://docs.python.org/3/library/itertools.html#itertools.dropwhile
>
> def less_than_10(x):
> return x < 10
>
> itertools.takewhile(less_than_10, itertools.count()) =>
> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
As the example demonstrates dropwhile() takes a function as its first
argument. To apply it to a sequence of tuples you could write
>>> items
[(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
>>> def first_is_one(t):
... return t[0] == 1
...
>>> list(itertools.dropwhile(first_is_one, items))
[(2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
However, if not all items where the predicate function evaluates to True are
at the beginning of the sequence:
>>> def second_is_one(t):
... return t[1] == 1
...
>>> list(itertools.dropwhile(second_is_one, items))
[(1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
If you want only the items where t[1] != 1 you need filter() or
itertools.filterfalse() (Python 2: itertools.ifilter or
itertools.ifilterfalse)
>>> list(itertools.filterfalse(second_is_one, items))
[(1, 2), (1, 3), (2, 2), (2, 3), (3, 2), (3, 3)]
> so I have a list I have created (converted from itertools). pm is
> permutations
>
>
> print(stats)
> [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 2), (1, 3, 4), (1, 3, 5), (1, 4,
> [2), (1, 4, 3), (1, 4, 5), (1, 5, 2), (1, 5, 3), (1, 5, 4), (2, 1, 3), (2,
> [1, 4), (2, 1, 5), (2, 3, 1), (2, 3, 4), (2, 3, 5), (2, 4, 1), (2, 4, 3),
> [(2, 4, 5), (2, 5, 1), (2, 5, 3), (2, 5, 4), (3, 1, 2), (3, 1, 4), (3, 1,
> [5), (3, 2, 1), (3, 2, 4), (3, 2, 5), (3, 4, 1), (3, 4, 2), (3, 4, 5), (3,
> [5, 1), (3, 5, 2), (3, 5, 4), (4, 1, 2), (4, 1, 3), (4, 1, 5), (4, 2, 1),
> [(4, 2, 3), (4, 2, 5), (4, 3, 1), (4, 3, 2), (4, 3, 5), (4, 5, 1), (4, 5,
> [2), (4, 5, 3), (5, 1, 2), (5, 1, 3), (5, 1, 4), (5, 2, 1), (5, 2, 3), (5,
> [2, 4), (5, 3, 1), (5, 3, 2), (5, 3, 4), (5, 4, 1), (5, 4, 2), (5, 4, 3)]
>
>
> I simply wanted to create an easy way to create summary stats of my stats
> list(poorly named). So in this case easy to check answers. so how many
> tuples in my list have a 1 in item[0] and how many don't. Then hoping to
> build on that for example how many have item[0] == 1 && (item[1] == 2 or
> item[1] == 4) etc.
>
> I can achieve it via an else if but that would become ugly quick.
>
> for item in stats:
> if item[0] == 1:
> nums += 1
> elif item[0] != 1:
> not_in += 1
> else:
> pass
Why would this become ugly? You can reshuffle it a bit to make it more
general:
>>> def count(items):
... t = f = 0
... for item in items:
... if item:
... t += 1
... else:
... f += 1
... return f, t
...
>>> count(t[1] == 1 for t in stats)
(48, 12)
>>> count(t[0] == 1 for t in stats)
(48, 12)
>>> count(t[0] in (1, 2) for t in stats)
(36, 24)
>>> count(sum(t) == 6 for t in stats)
(54, 6)
Alternatively collections.Counter() supports an arbitrary number of bins...
>>> import collections
>>> freq = collections.Counter(t[1] for t in stats)
>>> freq
Counter({1: 12, 2: 12, 3: 12, 4: 12, 5: 12})
...but you can easily reduce them:
>>> freq = collections.Counter(t[1] == 1 for t in stats)
>>> freq
Counter({False: 48, True: 12})
>>> one = freq[True]
>>> total = sum(freq.values())
>>> print("{} of {} ({}%) have t[1] == 1".format(one, total, one/total*100))
12 of 60 (20.0%) have t[1] == 1
More information about the Python-list
mailing list