Path: csiph.com!usenet.pasdenom.info!news.etla.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed1.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; 'python,': 0.02; 'else:': 0.03; 'algorithm': 0.04; '(even': 0.05; 'output': 0.05; 'problem:': 0.07; 'test,': 0.07; 'integers': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'spec': 0.09; 'unittest': 0.09; 'works.': 0.09; 'subject:Help': 0.11; 'python': 0.11; 'def': 0.12; 'jan': 0.12; '55,': 0.16; '67,': 0.16; '[10]': 0.16; '[])': 0.16; 'blocks': 0.16; 'builtins': 0.16; 'convey': 0.16; 'incremented': 0.16; 'input:': 0.16; 'integers,': 0.16; 'integers.': 0.16; 'iterable': 0.16; 'iterables': 0.16; 'iterators': 0.16; 'loop.': 0.16; 'loops': 0.16; 'next.': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'sequence.': 0.16; 'stumbled': 0.16; 'wrote:': 0.18; 'code.': 0.18; 'file,': 0.19; 'practices,': 0.19; '>>>': 0.22; 'code,': 0.22; 'input': 0.22; 'import': 0.22; 'coding': 0.22; 'separate': 0.22; 'print': 0.22; 'header:User-Agent:1': 0.23; 'integer': 0.24; 'subject:Code': 0.24; 'test.': 0.24; 'decide': 0.24; 'gets': 0.27; 'header:X-Complaints-To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; '(this': 0.29; 'am,': 0.29; 'compared': 0.30; 'forgot': 0.30; 'went': 0.31; 'code': 0.31; 'easier': 0.31; 'lines': 0.31; "skip:' 10": 0.31; 'comparison': 0.31; 'noted': 0.31; 'class': 0.32; 'lists': 0.32; 'interface': 0.32; 'beginning': 0.33; 'cases': 0.33; 'could': 0.34; 'problem': 0.35; 'possible.': 0.35; 'skip:s 30': 0.35; 'skip:u 20': 0.35; 'something': 0.35; 'objects': 0.35; 'test': 0.35; 'but': 0.35; 'otherwise.': 0.36; 'sequence': 0.36; 'yield': 0.36; 'next': 0.36; 'should': 0.36; 'list': 0.37; 'ahead': 0.38; 'generic': 0.38; 'initially': 0.38; 'version,': 0.38; 'to:addr :python-list': 0.38; 'rather': 0.38; '12,': 0.39; 'received:71': 0.39; 'to:addr:python.org': 0.39; 'received:org': 0.40; 'middle': 0.60; 'solve': 0.60; 'first': 0.61; 'happen': 0.63; 'user,': 0.69; 'increasing': 0.74; '92,': 0.84; 'clearer': 0.84; 'received:fios.verizon.net': 0.84; 'tem': 0.84; 'thing,': 0.91 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: Help me write better Code Date: Wed, 09 Jul 2014 14:46:48 -0400 References: <3a608dd2-d8bf-429e-af21-ce5ac8f18272@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: pool-71-175-90-87.phlapa.fios.verizon.net User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 In-Reply-To: <3a608dd2-d8bf-429e-af21-ce5ac8f18272@googlegroups.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 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: 96 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1404931649 news.xs4all.nl 2961 [2001:888:2000:d::a6]:36308 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:74272 On 7/9/2014 10:27 AM, sssdevelop wrote: > Hello, > > I have working code - but looking for better/improved code. Better coding practices, better algorithm :) > > Problem: Given sequence of increasing integers, print blocks of consecutive integers. > Input: [51, 53, 55, 67, 68, 91, 92, 93, 94, 99] > Outout: [67, 68], [91, 92, 93, 94] Recommendations: 1. If you are just beginning Python, use the current version, now 3.4. 2. Separate interface code that gets input and presents output from the function that processes the increasing sequence. The function should not care whether the ints come from a user, file, or calculation. 3. Think in terms of iterables and iterators rather than lists (this is clearer in 3.x, where some builtins have been converted). The function should not care what class is used to convey the sequence of numbers. This happens to make it easier to solve the 'pump-priming' problem you stumbled over. 4. For designing a loop, what is the loop invariant that you want, that will make writing the code easy. For this problem, "tem is a non-emptly list of consecutive integers". Remember that a list of one int qualifies. Using for loops with the proper iterable solves the other part of the loop invariant: the current item is the next item to be compared to the last item of tem. If tem is always non-empty, that comparison is always possible. 5. Remember that Python code is generic unless constrained. What should happen if the function gets non-int numbers, with or without an integer value? What should happen if the sequence is not increasing, but contains consecutive subsequences. For beginning code, one could decide to meet the spec given for input that meets the condition and not care otherwise. The code below works for any sequence (even infinite) of objects that can be incremented by 1 and compared to the next. 6. Write an automated test. For one test, something like this works. ci = consec([51, 53, 55, 67, 68, 91, 92, 93, 94, 99]) print(next(ci) == [67, 68], next(ci) == [91, 92, 93, 94]) but since you (properly) noted several test cases a = [51, 53, 55, 67, 68, 91, 92, 93, 94, 99] #a = [] #a = [10] #a = [10, 11, 12, 15] I went ahead and used unittest, at the cost of three lines of 'boilerplate' code. I added a case with a final consecutive sequence. Good thing, because it initially failed because I initially forgot to check tem after the loop. import unittest def consec(iterable): "Yield blocks of consecutive integers as a list." it = iter(iterable) first = next(it) tem = [first] for n in it: # tem is a non-empty list of consecutive ints if n == tem[-1] + 1: tem.append(n) else: if len(tem) >= 2: yield tem tem = [n] if len(tem) >= 2: yield tem class Test(unittest.TestCase): def test_consec(self): def eq(seq, blocks): self.assertEqual(list(consec(seq)), blocks) eq((), []) eq([1], []) eq([1,2,3], [[1,2,3]]) # block at beginning or end eq([-1, 1,2,3, 5], [[1,2,3]]) # block in middle eq((-1, 1,2,3, 5, 7,8,9, 11), [[1,2,3], [7,8,9]]) # 2 blocks unittest.main(verbosity=2) >>> test_consec (__main__.Test) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.016s OK -- Terry Jan Reedy