On 26/11/2021 22.17, Frank Millman wrote: > In my program I have a for-loop like this - > >>>> for item in x[:-y]: > ... [do stuff] > > 'y' may or may not be 0. If it is 0 I want to process the entire list > 'x', but of course -0 equals 0, so it returns an empty list. ...
> But in my actual program, both x and y are fairly long expressions, so > the result is pretty ugly. > > Are there any other techniques anyone can suggest, or is the only > alternative to use if...then...else to cater for y = 0? Here's hoping that this good-looking boy has not missed the point about "ugly". Is this the problem, re-stated to be fully explicit, with (almost) zero-complexity? [Zen of Python] >>> x = [ "a", "b", "c", "d", "e" ] >>> for y in [ 1, 2, 3, 4, 5 ]: ... print( y, x[ :-y ] ) ... 1 ['a', 'b', 'c', 'd'] 2 ['a', 'b', 'c'] 3 ['a', 'b'] 4 ['a'] 5 [] Whilst the code 'works', it lacks the 'zero-case' of what is not to be included - which is an overly-complicated way of saying: misses the 'all-case'. As observed, if we add a zero to the slice/loop-control that fails logically (and we get more religion: "the first shall be last, and the last shall be first". [Christian Bible]) >>> for y in [ 0, 1, 2, 3, 4, 5 ]: ... print( y, x[ :-y ] ) ... 0 [] 1 ['a', 'b', 'c', 'd'] 2 ['a', 'b', 'c'] 3 ['a', 'b'] 4 ['a'] 5 [] The problem, as expressed, is that whilst there is a negative of 1, ie -1, and other positive-integers, there is no (material) negative of 0, ie 0 == -0 == +0. (if the following seems pedantic and 'talking down', it is because I'm filleting a tutorial prepared for Python-Apprentices) Remember that 'salvation' may lie in the somewhat mysterious rules of slicing's default values. According to the Python rule-book (not exactly a religious text, but we must tend it with some fervor... [Built-in Types] https://docs.python.org/3/library/stdtypes.html?highlight=slice) « s[i] ith item of s, origin 0 (3) s[i:j] slice of s from i to j (3)(4) s[i:j:k] slice of s from i to j with step k (3)(5) ... (3) If i or j is negative, the index is relative to the end of sequence s: len(s) + i or len(s) + j is substituted. But note that -0 is still 0. » Which anticipates the problem 'here', and only rubs salt into the wound. Pressing on... « (4) The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j. If i or j is greater than len(s), use len(s). If i is omitted or None, use 0. If j is omitted or None, use len(s). If i is greater than or equal to j, the slice is empty. (5) The slice of s from i to j with step k is defined as the sequence of items with index x = i + n*k such that 0 <= n < (j-i)/k. In other words, the indices are i, i+k, i+2*k, i+3*k and so on, stopping when j is reached (but never including j). When k is positive, i and j are reduced to len(s) if they are greater. When k is negative, i and j are reduced to len(s) - 1 if they are greater. If i or j are omitted or None, they become “end” values (which end depends on the sign of k). Note, k cannot be zero. If k is None, it is treated like 1. » ...and so we see the open-closed nature of Python's ranges and range-alike objects! The 'secret' lies in the 'sins of omission'. As above, if either the 'start' or the 'stop' attribute is omitted, then it is treated as None, ie x[ :-y ] becomes x[ None:-y ] Thereafter we look at how None is interpreted. In the above example, the 'start' None becomes zero, thus: x[ :-y ] becomes x[ None:-y ] and thus x[ 0:-y ] The pertinent topic is the other end of the range. A 'stop' None will become len( x ), thus putting it together with the 'start' points, the short-hand form of a copy-operation is: x[ : ] which becomes x[ None:None ] and thus x[ 0:len( x ) ] Let's combine that with the idea of negative indexes/indices. Referring-back to (3) (above). If all of x is to be included: x[ :] is the way to go - but another way to express that is: x[ :len( x ) ] If the last item in x is to be excluded: x[ :-1 ] If the last two items ... excluded: x[ :-2 ] (etc) and another way to write those two specific examples is x[ :len( x ) - 1 ] and x[ :len( x ) - 2 ] and while we are taking things 'away' from the end of the iterable, the missing x[ :len( x ) ] is the same as x[ :len( x ) - 0 ] Thus, by now, you've leaped ahead of me, to: >>> for y in [ 0, 1, 2, 3, 4, 5 ]: ... print( y, x[ :len( x ) - y ] ) ... 0 ['a', 'b', 'c', 'd', 'e'] 1 ['a', 'b', 'c', 'd'] 2 ['a', 'b', 'c'] 3 ['a', 'b'] 4 ['a'] 5 [] and yes, if computing y is expensive/ugly, for extra-credit, calculate the 'stop' value outside/prior-to the for-loop! -- Regards, =dn -- https://mail.python.org/mailman/listinfo/python-list