From: Terry Reedy on 20 Jul 2010 17:58 A Python newcomer asked this question on python-ideas list. I am answering here for the benefit of others. Example: building a string res with commas separating substrings s from some sequence. Either the first item added must be s versus ', '+s or the last must be s versus s+', '. For building strings, of course, the join method solves the problem, adding n-1 separators between n items. items = ['first', 'second', 'last'] print(', '.join(items)) #first, second, last DISCLAIMER: All of the following code chunks produce the same result, for the purpose of illustration, but they are NOT the way to build a string result with dependable efficiency. To treat the first item differently, either peel it off first ... it = iter(items) try: # protect against empty it, simplify if know not res = next(it) for s in it: res += ', ' + s except StopIteration: res = '' print(res) # first, second, last or use a flag. res = '' First = True for s in items: if First: res=s First=False else: res += ', ' + s print(res) # first, second, last There is no way, in general, to know whether next(it) will yield another item after the current one. That suggests that the way to know whether an item is the last or not is try to get another first, before processing the current item. One approach is to look ahead ... it = iter(items) res = '' try: cur = next(it) for nxt in it: # cur is not last res += cur + ', ' cur = nxt else: # cur is last item res += cur except StopIteration: pass print(res) # first, second, last Another is to add a unique sentinel to the sequence. Last = object() items.append(Last) # so not empty, so no protection against that needed it = iter(items) res = '' cur = next(it) for nxt in it: if nxt is not Last: res += cur + ', ' cur = nxt else: res += cur print(res) # first, second, last It makes sense to separate last detection from item processing so last detection can be put in a library module and reused. def o_last(iterable): " Yield item,islast pairs" it = iter(iterable) cur = next(it) for nxt in it: yield cur,False cur = nxt else: yield cur,True def comma_join(strings): res = '' for s,last in o_last(strings): res += s if not last: res += ', ' return res print(comma_join(['first', 'second', 'last'])) print(comma_join(['first', 'last'])) print(comma_join(['last'])) print(comma_join([])) # first, second, last # first, last # last # -- Terry Jan Reedy
From: Peter Otten on 21 Jul 2010 04:16 Terry Reedy wrote: > It makes sense to separate last detection from item processing so last > detection can be put in a library module and reused. Here's an extension of your idea that puts the detection of both the first and the last item into a generator: def mark_first(items): items = iter(items) yield True, next(items) for item in items: yield False, item def mark_last(items): items = iter(items) prev = next(items) for cur in items: yield False, prev prev = cur yield True, prev def mark_ends(items): return ((head, tail, item) for head, (tail, item) in mark_first(mark_last(items))) for items in "", "a", "ab", "abc": print list(items), "-->", list(mark_ends(items)) for first, last, item in mark_ends("abc"): if first: print "first", if last: print "last", print item It may not be the most efficient approach, but it looks clean.
|
Pages: 1 Prev: linux console command line history Next: Multidimensional Fitting |