459,277 Members | 1,433 Online
Need help? Post your question and get tips & solutions from a community of 459,277 IT Pros & Developers. It's quick & easy.

# enumerate improvement proposal

 P: n/a I think that it would be handy for enumerate to behave as such: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step This allows much more flexibility than in the current enumerate, tightens up code in many cases, and seems that it would break no existing code. Yes, I have needed this behavior with enumerate, like tonight and the current example. I put the "step" parameter in for conceptual symmetry with slicing. Here is a case use (or is it use case?): # with the proposed enumerate import operator def in_interval(test, bounds, first=1, reverse=False): op = operator.gt if reverse else operator.lt # python 2.5 bounds = sorted(bounds, reverse=reverse) for i, bound in enumerate(bounds, first): if op(test, bound): return i return i + 1 # with the existing enumerate import operator def in_interval(test, bounds, first=1, reverse=False): op = operator.gt if reverse else operator.lt # python 2.5 bounds = sorted(bounds, reverse=reverse) for i, bound in enumerate(bounds): if op(test, bound): return i + first return i + first + 1 py# eg .... pyin_interval(8, bounds) 2 pyin_interval(1, bounds) 1 pyin_interval(1, bounds, reverse=True) 5 pyin_interval(8, bounds, reverse=True) 4 pyin_interval(20, bounds, reverse=True) 2 Of course, I haven't used step here. Even in this trivial example the proposed enumerate cleans the code and logic, eliminating a couple of plus signs. For this real-world example, the practical requirement for reversing the bins obfuscates somewhat the de-obfuscation provided by the proposed enumerate. But I think that it might be obvious that the proposed enumerate could help significantly in cases a bit more complicated than this one. Any thoughts? James Oct 29 '06 #1
21 Replies

 P: n/a James Stroud wrote: I think that it would be handy for enumerate to behave as such: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step This allows much more flexibility than in the current enumerate, tightens up code in many cases, and seems that it would break no existing code. Yes, I have needed this behavior with enumerate, like tonight and the current example. I put the "step" parameter in for conceptual symmetry with slicing. Here is a case use (or is it use case?): # with the proposed enumerate import operator def in_interval(test, bounds, first=1, reverse=False): op = operator.gt if reverse else operator.lt # python 2.5 bounds = sorted(bounds, reverse=reverse) for i, bound in enumerate(bounds, first): if op(test, bound): return i return i + 1 # with the existing enumerate import operator def in_interval(test, bounds, first=1, reverse=False): op = operator.gt if reverse else operator.lt # python 2.5 bounds = sorted(bounds, reverse=reverse) for i, bound in enumerate(bounds): if op(test, bound): return i + first return i + first + 1 py# eg ... pyin_interval(8, bounds) 2 pyin_interval(1, bounds) 1 pyin_interval(1, bounds, reverse=True) 5 pyin_interval(8, bounds, reverse=True) 4 pyin_interval(20, bounds, reverse=True) 2 Of course, I haven't used step here. Even in this trivial example the proposed enumerate cleans the code and logic, eliminating a couple of plus signs. For this real-world example, the practical requirement for reversing the bins obfuscates somewhat the de-obfuscation provided by the proposed enumerate. But I think that it might be obvious that the proposed enumerate could help significantly in cases a bit more complicated than this one. Any thoughts? James After a brief reflection, I realized that I just described a "for-to-step-do" style loop one might find in many other languages, most notably BASIC. James Oct 29 '06 #2

 P: n/a James Stroud wrote: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step that's spelled izip(count(start), sequence) in today's Python. def in_interval(test, bounds, first=1, reverse=False): why is it this function's job to add an offset to the actual sequence index? Oct 29 '06 #3

 P: n/a Fredrik Lundh wrote: why is it this function's job to add an offset to the actual sequence index? The code is for an economist. She is insistent on starting with the first bin as 1. I'm guessing, practically, binning linerizes data and the bin number may potentially become a divisor or perhaps the operand in a logarithm. James Oct 29 '06 #4

 P: n/a Fredrik Lundh wrote: James Stroud wrote: >def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step that's spelled izip(count(start), sequence) in today's Python. def in_interval(test, bounds, first=1, reverse=False): why is it this function's job to add an offset to the actual sequence index? BTW, thank you for your tip. James Oct 29 '06 #5

 P: n/a James Stroud wrote: The code is for an economist. She is insistent on starting with the first bin as 1. leaky abstractions in reverse, in other words? that's not a good design approach. Oct 29 '06 #6

 P: n/a Fredrik Lundh wrote: James Stroud wrote: >The code is for an economist. She is insistent on starting with thefirst bin as 1. leaky abstractions in reverse, in other words? that's not a good design approach. I'm not sure I understand what "leaky abstractions" means. I am helping someone with dubious programming skills make sense of a pile of code they wrote--code which getting a little unwieldy to debug. I think "design approach" can't really apply here. The idea is to make it comprehensible at some level. I'm still curious what you mean by "leaky abstractions". Please explain. James Oct 29 '06 #7

 P: n/a James Stroud wrote: I think that it would be handy for enumerate to behave as such: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step This allows much more flexibility than in the current enumerate, tightens up code in many cases, and seems that it would break no existing code. Yes, I have needed this behavior with enumerate, like tonight and the current example. I put the "step" parameter in for conceptual symmetry with slicing. Here is a case use (or is it use case?): I don' think you have a use case here: # untested def find_interval(value, bounds, funny_offset=0, reverse=False): bounds = sorted(bounds) if reverse: index = len(bounds) - bisect.bisect_left(bounds, value) else: index = bisect.bisect_right(bounds, value) return index + funny_offset You can tell by its name which of the arguments I would have omitted :-) Of course, I haven't used step here. That seems to be typical. The only use case I've ever come across is start=1 for output aimed at a human reader. Even in this trivial example the proposed enumerate cleans the code and logic, eliminating a couple of plus signs. For this real-world example, the practical requirement for reversing the bins obfuscates somewhat the de-obfuscation provided by the proposed enumerate. But I think that it might be obvious that the proposed enumerate could help significantly in cases a bit more complicated than this one. Of course you get these claimed advantages from a self-written function, too. Any thoughts? You have my support for adding a start parameter to enumerate(). I fear it won't make a difference. Peter Oct 29 '06 #8

 P: n/a James Stroud wrote: I think that it would be handy for enumerate to behave as such: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step This allows much more flexibility than in the current enumerate, tightens up code in many cases, and seems that it would break no existing code. Yes, I have needed this behavior with enumerate, like tonight and the current example. I put the "step" parameter in for conceptual symmetry with slicing. Here is a case use (or is it use case?): Incidentally, I yesterday wrote a patch giving enumerate() a start parameter (and, more importantly, changing it so that it doesn't wraparound at sys.maxint). It can be found here: https://sourceforge.net/tracker/?fun...&group_id=5470 Georg Oct 29 '06 #9

 P: n/a James Stroud >print enumerate("ABCDE") >>print list(enumerate("ABCDE")) [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')] >def obstinate_economist_enumerate(items): ... seq = [(i+1, x) for (i, x) in enumerate(items)] ... return iter(seq) ... >>print obstinate_economist_enumerate("ABCDE") >>print list(obstinate_economist_enumerate("ABCDE")) [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')] This doesn't produce an 'enumerate' object; if you really want that, you could subclass 'enumerate', but it seems the above function does what you want. -- \ "I installed a skylight in my apartment. The people who live | `\ above me are furious!" -- Steven Wright | _o__) | Ben Finney Oct 29 '06 #10

 P: n/a Ben Finney >print enumerate("ABCDE") >>print list(enumerate("ABCDE")) [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')] >def obstinate_economist_enumerate(items): ... seq = [(i+1, x) for (i, x) in enumerate(items)] ... return iter(seq) ... >>print obstinate_economist_enumerate("ABCDE") >>print list(obstinate_economist_enumerate("ABCDE")) [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')] An improvement: using a generator so as not to unnecessarily create an intermediate list from the initial enumerator: >>def obstinate_economist_enumerate(items): ... enum_iter = iter((i+1, x) for (i, x) in enumerate(items)) ... return enum_iter ... >>print obstinate_economist_enumerate("ABCDE") >>print list(obstinate_economist_enumerate("ABCDE")) [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')] -- \ "If sharing a thing in no way diminishes it, it is not rightly | `\ owned if it is not shared." -- Saint Augustine | _o__) | Ben Finney Oct 29 '06 #11

 P: n/a Fredrik Lundh wrote: James Stroud wrote: >The code is for an economist. She is insistent on starting with thefirst bin as 1. leaky abstractions in reverse, in other words? that's not a good design approach. Okay, I've googled "leaky abstractions" (as was probably your intended affect with your silence), read the famous essay, and still don't know what you mean and how it applies to what I have described. Do you plan to justify your statement or emptily accuse people of violating esoteric principles? James -- James Stroud UCLA-DOE Institute for Genomics and Proteomics Box 951570 Los Angeles, CA 90095 http://www.jamesstroud.com/ Oct 30 '06 #12

 P: n/a Ben Finney wrote: > >>def obstinate_economist_enumerate(items): ... enum_iter = iter((i+1, x) for (i, x) in enumerate(items)) ... return enum_iter iter is redundant here. def natural_enumerate_improvement(items, start=0): return ((i+start, x) for (i, x) in enumerate(items)) - Anders Oct 30 '06 #13

 P: n/a Okay, I've googled "leaky abstractions" (as was probably your intended affect with your silence), read the famous essay, and still don't know what you mean and how it applies to what I have described. Do you plan to justify your statement or emptily accuse people of violating esoteric principles? While I can't claim to know what the effbot thinks (the skull-socks-wearing-python-coder-mindlink-technology is yet to be developed), I think it's pretty clear what he is after here: Computers compute offsets into data zero-based. Some languages like pascal completely abstract that away from the user, but python doesn't. So if your colleague/boss/whatever insists on indices being one-based, this abstraction you introduced for her pretty fast leaks pretty badly. Consider this simple example: for offset, item in enumerate(some_list, start=1): if item.is_the_chosen_one(): chosen_one_offset = offset the_chosen_one = some_list[chosen_one_offset] And bang, its Judas not Petrus who gets the pearly gates inc. stock options. Diez Oct 30 '06 #14

 P: n/a Steve Holden wrote: How could you end up marrying someone who counts from one and not zero? ;-) She's the only other person I've ever met who used vi key binding at the command line. James -- James Stroud UCLA-DOE Institute for Genomics and Proteomics Box 951570 Los Angeles, CA 90095 http://www.jamesstroud.com/ Oct 31 '06 #17

 P: n/a * James Stroud wrote (on 10/30/2006 4:39 PM): Steve Holden wrote: >How could you end up marrying someone who counts from one and notzero? ;-) She's the only other person I've ever met who used vi key binding at the command line. James Well, there's your problem. You need to C-x C-f a new mate. :) Mark (Emacs rules) Oct 31 '06 #18

 P: n/a Mark Elston

 P: n/a James Stroud wrote: Steve Holden wrote: How could you end up marrying someone who counts from one and not zero? ;-) She's the only other person I've ever met who used vi key binding at the command line. Wow. Now I see! It's only Python. Just add one to indices where appropriate, buy her chocolates. Don't say a thing when you squelch your seventh off-by-one error. Look interested in the shoe store. (even for the fifth shoe, of the third store). - *Your partner does vi* Whoa! - Paddy :-) Oct 31 '06 #20

 P: n/a On Mon, 30 Oct 2006 23:42:16 +0000, Steve Holden wrote: Divorce is obviously the only answer. How could you end up marrying someone who counts from one and not zero? ;-) "Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration." (Stan Kelly-Bootle) -- Steven. Oct 31 '06 #21

 P: n/a James Stroud wrote: I think that it would be handy for enumerate to behave as such: def enumerate(itrbl, start=0, step=1): i = start for it in itrbl: yield (i, it) i += step I proposed something like this long ago and Guido has already rejected it. Part of the reason is that it doesn't match his mental model of enumerate being about pairing sequence elements with their indices. Another reason is that the syntax has more than one obvious interpretation: enumerate('abcdef', 2) -- (2, 'c'), (3, 'd'), ... enumerate('abcdef', 2) -- (0, 'c'), (1, 'd'), ... enumerate('abcdef', 2) -- (2, 'a'), (2, 'b'), ... Also, the order of arguments is odd in comparison with the output order -- this suggests a syntax like enumerate(2, 'abcdef') --(2, 'a'), (3, 'b') ... FWIW, it is not hard to roll-your-own with something like: for pagenum, page in izip(count(1), book): ... The izip/count combination runs at C speed, matches enumerate() in its efficiency, and is arguably clearer in expressing its intended behavior. Raymond Oct 31 '06 #22

### This discussion thread is closed

Replies have been disabled for this discussion.