Path: csiph.com!usenet.pasdenom.info!news.redatomik.org!newsfeed.xs4all.nl!newsfeed2.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'subject:not': 0.03; 'else:': 0.03; 'elif': 0.05; '(python': 0.07; 'ugly': 0.07; '3),': 0.09; '[1,': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'subject:using': 0.09; 'def': 0.12; '(1,': 0.16; '(2,': 0.16; '(3,': 0.16; '(converted': 0.16; '1),': 0.16; '12)': 0.16; '2),': 0.16; '3)]': 0.16; '4),': 0.16; '5),': 0.16; '[2,': 0.16; 'argument.': 0.16; 'collections': 0.16; 'evaluates': 0.16; 'item:': 0.16; 'item[0]': 0.16; 'itertools': 0.16; 'received:80.91.229.3': 0.16; 'received:dip0.t-ipconnect.de': 0.16; 'received:plane.gmane.org': 0.16; 'received:t-ipconnect.de': 0.16; 'sequence:': 0.16; 'stats': 0.16; 'subject:fails': 0.16; 'true:': 0.16; 'wrote:': 0.18; 'bit': 0.19; '>>>': 0.22; 'example': 0.22; 'import': 0.22; 'header:User-Agent:1': 0.23; 'example.': 0.24; 'skip:l 30': 0.24; 'pass': 0.26; 'header:X -Complaints-To:1': 0.27; 'function': 0.29; 'subject:list': 0.30; 'tuples': 0.31; 'summary': 0.32; 'url:python': 0.33; 'beginning': 0.33; 'could': 0.34; "can't": 0.35; 'created': 0.35; 'but': 0.35; 'sequence': 0.36; 'url:org': 0.36; 'list': 0.37; 'easily': 0.37; 'filter': 0.38; 'url:library': 0.38; 'to:addr:python-list': 0.38; '12,': 0.39; 'to:addr:python.org': 0.39; 'received:org': 0.40; 'how': 0.40; 'easy': 0.60; 'url:3': 0.61; 'simply': 0.61; 'first': 0.61; 'become': 0.64; 'more': 0.64; 'total': 0.65; 'hoping': 0.75; 'demonstrates': 0.84; 'total,': 0.84 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Peter Otten <__peter__@web.de> Subject: Re: itertools py3.4 - filter list using not equal - fails as bool Date: Wed, 13 May 2015 09:40:05 +0200 Organization: None References: <05defef5-74aa-4a5d-b7e7-9b521512152c@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset="ISO-8859-1" Content-Transfer-Encoding: 7Bit X-Gmane-NNTP-Posting-Host: p57bd9b5c.dip0.t-ipconnect.de User-Agent: KNode/4.13.3 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20+ Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 112 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1431502814 news.xs4all.nl 2938 [2001:888:2000:d::a6]:48233 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:90537 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