5

Suppose I would like to loop over an array and within the loop index the array forward and backward for all of its indices like so:

x = np.random.uniform(size=600)
for i in range(len(x)):
    dot = np.dot(x[:-i], x[i:])

Now this doesn't work, because x[:-0] is just like x[:0] which gives []. I could handle the zero case separately but was wondering whether there's a more pythonic way of doing this.

2 Answers 2

9

Use an end of slice value of -i or None. If i is non-zero, then it's just -i, but if it's 0, then -0 is falsy, and it evaluates and returns the second term, None, which means "run to end of sequence". This works because foo[:None] is equivalent to foo[:], when you omit that component of the slice it becomes None implicitly, but it's perfectly legal to pass None explicitly, with the same effect.

So your new line would be:

dot = np.dot(x[:-i or None], x[i:])
Sign up to request clarification or add additional context in comments.

4 Comments

It pairs well with "truthy". :-) I prefer to use it over "true" and "false", because frankly, in Python, you rarely care about the actual values True and False, you just care whether a value is true or false for boolean evaluation purposes; truthy or falsy makes it clear you care about the meaning, not the specific value.
I see you've played knifey spoony before youtube.com/watch?v=mcE0aAhbVFc
Neaty. I would probably go with [:len(x) - i], but that's only because I'm paranoid about relying on boolean evaluation of non-booleans.
@RuneLyngsoe: Yeah, that also works, though it would be slower (particularly if you didn't precompute len(x) outside the loop and store it off; the overhead for calling built-in functions like that is surprisingly high given how little work they actually do). -i or None only adds a single implicit boolean evaluation (about the cheapest thing CPython can do shy of the pass statement) to the common case, where len(x) - i adds a built-in lookup, built-in call, and subtract operation to every usage (local load and subtract if you precache would cost only a trivial amount more at least).
2

Why don't you just use the length information:

length = len(x)

for i in range(length):
    dot = np.dot(x[:length-i], x[i:])

3 Comments

I think they want a slice smaller than the length of x
@Pureferret it is smaller than the length of x (except for the first iteration)
yup, this is equivalent to ShadowRanger's solution, thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.