4

So one issue I discovered with python is that it is not very user-friendly to create nested loops each with their own indexes.

How would I write the Python-equivalent of this Java code:

for(int i = 0; i < array.length-2; i++){
    for(int j = i+1; j < array.length-1; j++){ 
       for(int k = j+1; k < array.length; k++){

Notice how I reference the counter value of the predecessor's for each nested loop. I tried using:

for idx, val in enumerate(nums[:-2]):

but it seems like idx will always start at 0 rather than start at the predecessor's index value. Is there a better solution besides maintaining separate counter variables?

btrballin
  • 1,420
  • 3
  • 25
  • 41
  • 3
    I smell an XY problem here. What are you trying to solve? Often there are no 1-1 mappings between different languages (there is here), and there may even be a better pythonic way of solving the same problem that Java does not offer. – cs95 Dec 27 '17 at 09:55
  • 4
    For reference, it isn't hard at all. `for i in range(len(arr) - 2): for j in range(i + 1, len(arr) - 1): for k in range(j + 1, len(arr)): ...` using the nested loops with `range` would be the obvious way of doing it. – cs95 Dec 27 '17 at 09:56
  • 2
    this might be related: https://stackoverflow.com/questions/41521725/iterating-over-multiple-indices-with-i-j-k-in-a-pythonic-way – hiro protagonist Dec 27 '17 at 09:56
  • The goal is just to iterate through an array and do something with each triplet. Looks like instead of using an enhanced for-loop which references the current element directly, I just use the index values to reference the element from the array (ie array[i] vs val) – btrballin Dec 27 '17 at 10:04

4 Answers4

6

From [Python.Docs]: Built-in Functions - enumerate(iterable, start=0) (emphasis is mine):

The __next__() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over iterable.

Example:

num = [0, 2, 4, 6, 8]
start = 2
for idx, val in enumerate(num[start:], start=start):
    print("Index: {0:d}, Element: {1:d}".format(idx, val))

Output:

Index: 2, Element: 4
Index: 3, Element: 6
Index: 4, Element: 8
CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • I would go for this version since if I'm not mistaken, enumerate returns an iterator, which is faster to iterate through than a list (returned by range). :) – IMCoins Dec 27 '17 at 10:11
  • 1
    @IMCoins: In *Py3* `range` also returns an iterator (behavior that in *Py2* is available via `xrange`). I don't think that iterators are faster than lists (iterator values are produced on the fly, while list is already there), the great advantage is memory consumption. – CristiFati Dec 27 '17 at 10:27
2

It's simple.

for i in range(0,len(array)-2):
    for j in range(i+1,len(array)-1):
        for k in range(j+1,len(array)):
            print k
        print j
    print i
babygame0ver
  • 447
  • 4
  • 16
2

It's very simple to do that using range or xrange. Here's how you do it.

Java version:

for(int i = 0; i < array.length-2; i++) {
    for(int j = i+1; j < array.length-1; j++) { 
        for(int k = j+1; k < array.length; k++) {

Python version:

for i in xrange(0,len(arr)-2):
    for j in xrange(i+1, len(arr)-1):
       for k in xrange(j+1, len(arr)):

I hope that helps!

Sourav Badami
  • 769
  • 7
  • 13
2

Although completely answered, I just wanted to add an example with a nested enumerate to cover the original question. One important thing to have in mind is that the start parameter on the enumerate signature enumerate(iterable, start=0) won't skip the actual iterable. If you want to nest loops with enumerate in a scenario in which you do not want to re-use previous loops indexes, e.g., consider the array=[1, 2, 3, 4] for the original question, you can't just make:

for first_idx, first in enumerate(array):
    for second_idx, second in enumerate(array, first_idx + 1):
        for third_idx, third in enumerate(array, second_idx + 1):
            print(first, second, third)

As you will have the first iterations:

1 1 1
1 1 2
1 1 3
1 1 4
...

Instead, you have to:

for first_idx, first in enumerate(array):
    for second_idx, second in enumerate(array[first_idx + 1:], first_idx + 1):
        for third_idx, third in enumerate(array[second_idx + 1:], second_idx + 1):
            print(first, second, third)

It will correctly print:

1 2 3
1 2 4
1 3 4
2 3 4
Eduardo
  • 4,282
  • 2
  • 49
  • 63