Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #90503 > unrolled thread

itertools py3.4 - filter list using not equal - fails as bool

Started bySayth Renshaw <flebber.crue@gmail.com>
First post2015-05-12 15:43 -0700
Last post2015-05-13 06:58 -0700
Articles 4 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  itertools py3.4 - filter list using not equal - fails as bool Sayth Renshaw <flebber.crue@gmail.com> - 2015-05-12 15:43 -0700
    Re: itertools py3.4 - filter list using not equal - fails as bool MRAB <python@mrabarnett.plus.com> - 2015-05-13 00:22 +0100
    Re: itertools py3.4 - filter list using not equal - fails as bool Peter Otten <__peter__@web.de> - 2015-05-13 09:40 +0200
      Re: itertools py3.4 - filter list using not equal - fails as bool Sayth Renshaw <flebber.crue@gmail.com> - 2015-05-13 06:58 -0700

#90503 — itertools py3.4 - filter list using not equal - fails as bool

FromSayth Renshaw <flebber.crue@gmail.com>
Date2015-05-12 15:43 -0700
Subjectitertools py3.4 - filter list using not equal - fails as bool
Message-ID<05defef5-74aa-4a5d-b7e7-9b521512152c@googlegroups.com>
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

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
    

myString = "i have {a} in and {b} so the percentage is {c}%".format(a=nums, b=not_in, c=(nums/(nums + not_in)))

I thought dropwhile from the docs appeared a good option but it returns bool.

answer = listb.extend(itertools.dropwhile(item[0] != 1, stats))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-130-70c93104d1c5> in <module>()
----> 1 answer = listb.extend(itertools.dropwhile(item[0] != 1, stats))

TypeError: 'bool' object is not callable

Think I am making this hard somewhere that it is actually easy. 

As an aside do I really need to convert the iterator object to a list to create and summarize iterator contents?

Currently I have created a function to achieve this as below.

def myGen(parcel):
    x = []
    [x.append(y) for y in parcel]
    return x

myPerm = pm(range(1,6),3)

stats = myGen(myPerm)

[toc] | [next] | [standalone]


#90504

FromMRAB <python@mrabarnett.plus.com>
Date2015-05-13 00:22 +0100
Message-ID<mailman.425.1431472972.12865.python-list@python.org>
In reply to#90503
On 2015-05-12 23:43, 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
>
> 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
>
>
> myString = "i have {a} in and {b} so the percentage is {c}%".format(a=nums, b=not_in, c=(nums/(nums + not_in)))
>
> I thought dropwhile from the docs appeared a good option but it returns bool.
>
> answer = listb.extend(itertools.dropwhile(item[0] != 1, stats))
> ---------------------------------------------------------------------------
> TypeError                                 Traceback (most recent call last)
> <ipython-input-130-70c93104d1c5> in <module>()
> ----> 1 answer = listb.extend(itertools.dropwhile(item[0] != 1, stats))
>
> TypeError: 'bool' object is not callable
>
That evaluates:

     item[0] != 1

which returns True or False. Apparently, "item" happens to be bound to
something that can be subscripted.

It then calls:

     itertools.dropwhile(..., stats)

passing the bool as the first argument (the predicate) of dropwhile.

When it tries to test the first item from stats, it discovers that the
predicate is not callable; it's a bool.

Result: TypeError!

And another point: a list's "extend" method modifies the list and then
returns None, so "answer" will be None.

> Think I am making this hard somewhere that it is actually easy.
>
> As an aside do I really need to convert the iterator object to a list to create and summarize iterator contents?
>
> Currently I have created a function to achieve this as below.
>
> def myGen(parcel):
>      x = []

Don't use a list comprehension like this:

>      [x.append(y) for y in parcel]

Do this instead:

     for y in parcel:
         x.append(y)

or, alternatively, this:

     x.extend(parcel)

>      return x
>
> myPerm = pm(range(1,6),3)
>
> stats = myGen(myPerm)
>

[toc] | [prev] | [next] | [standalone]


#90537

FromPeter Otten <__peter__@web.de>
Date2015-05-13 09:40 +0200
Message-ID<mailman.435.1431502814.12865.python-list@python.org>
In reply to#90503
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


[toc] | [prev] | [next] | [standalone]


#90548

FromSayth Renshaw <flebber.crue@gmail.com>
Date2015-05-13 06:58 -0700
Message-ID<4a6fb545-15e1-450f-bb0a-ee8ad97296ee@googlegroups.com>
In reply to#90537
Thank You for the explanations.

I found this counter implementation is really cool and easily adaptable to more solutions.

Thanks
> 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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web