0

I have a list of lists as shown below. I want to iterate the list and for each list item with 'yes' at index 1, I want to update index 2 with count of occurrences of 'no' before I get another yes and then add add 1 to it. I don't know how to iterate over a range with a while to stop when I encounter another yes.

I've simplified the data in the Problem and Answer below, however here is the code I was using against the object to try and accomplish.

Problem

fullchart = [
    [1, 'yes', 0],
    [2, 'no', 0],
    [3, 'no', 0],
    [4, 'yes', 0],
    [5, 'no', 0],
    [6, 'no', 0],
    [7, 'yes', 0],
    [8, 'no', 0],
    [9, 'yes', 0]
]

Expected Output

[
    [1, 'yes', 3],
    [2, 'no', 0],
    [3, 'no', 0],
    [4, 'yes', 3],
    [5, 'no', 0],
    [6, 'no', 0],
    [7, 'yes', 2],
    [8, 'no', 0],
    [9, 'yes', 1]
]

Code

end_page = 0

for i in range(len(fullchart)):
    end_page = 0
    #pprint.pprint(fullchart[i][1])
    if fullchart[i][1] == 'yes':
        for b in range(i+1, len(fullchart)):
            print(b)
            if fullchart[i+1][1] == 'no':
                end_page += 1
                print('printing end_page')
                print(end_page)
        fullchart[i][3] == end_page
    else:
        pass
RichieV
  • 5,103
  • 2
  • 11
  • 24
NWS
  • 33
  • 5

4 Answers4

3

You can keep track of the last index with 'yes' and update the list in-place.

base_idx = 0
for i, (_, bool, _) in enumerate(L):
    if bool == 'yes':
        L[base_idx][2] = i - base_idx
        base_idx = i
L[base_idx][2] = i - base_idx + 1

print(*L, sep='\n')

Output

[1, 'yes', 3]
[2, 'no', 0]
[3, 'no', 0]
[4, 'yes', 3]
[5, 'no', 0]
[6, 'no', 0]
[7, 'yes', 2]
[8, 'no', 0]
[9, 'yes', 1]
RichieV
  • 5,103
  • 2
  • 11
  • 24
1

I think what you are looking for is break. Once you find the next "yes", then you want to capture that value and break out of the nested for loop.


fullchart = [
[1, 'yes', 0],
[2, 'no', 0],
[3, 'no', 0],
[4, 'yes', 0],
[5, 'no', 0],
[6, 'no', 0],
[7, 'yes', 0],
[8, 'no', 0],
[9, 'yes', 0]
]
end_page = 0


for i in range(len(fullchart)):
    end_page = 0
    if fullchart[i][1] == 'yes':
        print(f'checking.. i={i}')
        for b in range(i+1, len(fullchart)):
            print(f'\tchecking.. b={b}')
            if fullchart[b][1] == 'no':
                end_page += 1
                # print('printing end_page')
                # print(end_page)
            else:
                fullchart[i][2] = end_page+1
                break

    else:
        pass
print(fullchart)

Output

checking.. i=0
        checking.. b=1
        checking.. b=2
        checking.. b=3
checking.. i=3
        checking.. b=4
        checking.. b=5
        checking.. b=6
checking.. i=6
        checking.. b=7
        checking.. b=8
checking.. i=8
[[1, 'yes', 3], [2, 'no', 0], [3, 'no', 0], [4, 'yes', 3], [5, 'no', 0], [6, 'no', 0], [7, 'yes', 2], [8, 'no', 0], [9, 'yes', 0]]
Brennan
  • 504
  • 3
  • 14
  • 1
    Since your inner loop already checked the items with 'no', you could skip those items in the outer loop by changing the pointer `i = b` before `break` and changing that outer loop to `while i < len(fullchart):` – RichieV Sep 28 '20 at 06:06
  • Break is the concept I was looking for. Thanks. – NWS Sep 29 '20 at 00:39
1

Instead of using while statement, why don't you use for loop and traverse through the loop from the last to the first. That way you can count for each no until you get to the yes.

This solution does the loop only once. You don't need a nested loop. It is costly and bad coding.

Here's the code to do that:

a = [
[1, 'yes', 0],
[2, 'no', 0],
[3, 'no', 0],
[4, 'yes', 0],
[5, 'no', 0],
[6, 'no', 0],
[7, 'yes', 0],
[8, 'no', 0],
[9, 'yes', 0]
]

x = len(a)
yes = 0
for i in range(-1,-x-1,-1):
    print (a[i][1])
    if a[i][1] == 'yes':
        a[i][2] = yes+1
        yes = 0
    elif a[i][1] == 'no':
        yes +=1
    print (a[i],yes)
print (a)

The output of this will be:

[[1, 'yes', 3], [2, 'no', 0], [3, 'no', 0], [4, 'yes', 3], [5, 'no', 0], [6, 'no', 0], [7, 'yes', 2], [8, 'no', 0], [9, 'yes', 1]]

Formatted way to look at the data similar to your desired result will be:

[
 [1, 'yes', 3], 
 [2, 'no',  0], 
 [3, 'no',  0], 
 [4, 'yes', 3], 
 [5, 'no',  0], 
 [6, 'no',  0], 
 [7, 'yes', 2], 
 [8, 'no',  0], 
 [9, 'yes', 1]
]
Joe Ferndz
  • 8,417
  • 2
  • 13
  • 33
  • Reversing the list is a good idea, this reminded me of a similar [answer](https://stackoverflow.com/a/22820689/6692898) for a forward-looking rolling window in `pandas` – RichieV Sep 28 '20 at 06:17
  • Agree, in pandas this will be much simpler. – Joe Ferndz Sep 28 '20 at 06:21
0

You can use itertools.groupby() to group by yes and no and some simple logic allows you get the len() of the no group to assign to the previous yes item (Note: this assumes that yes is a singular item and first), e.g.:

In []:
import itertools as it

for k, g in it.groupby(fullchart, lambda d: d[1]):
    if k == 'yes':
        y = next(g)
        y[2] = 1
    else:
        y[2] += len(list(g))

print(fullchart)

Out[]:
[[1, 'yes', 3],
 [2, 'no', 0],
 [3, 'no', 0],
 [4, 'yes', 3],
 [5, 'no', 0],
 [6, 'no', 0],
 [7, 'yes', 2],
 [8, 'no', 0],
 [9, 'yes', 1]]
AChampion
  • 29,683
  • 4
  • 59
  • 75