3

Apologies if this is already covered in another thread. I'm a bit new with Python (3, specifically), so perhaps the answer was given to a conceptually similar question and I missed the relevance.

I am looping through a list of lists, similar to the following:

biglist = [[a, b, x, d], [a, b, x, d], [a, b, y, d], [a, b, y, d], [a, b, z, d], [a, b, x, d]]

I would like to conditionally perform certain actions whenever the third element in a given sublist is different than the third element in the previous sublist. In the above example, this would happen for the third sublist (y != x), the fifth sublist (z != y) and the sixth sublist (x != z).

Whenever such non-matches occur, I would like to modify the corresponding first element in the current sublist. (Note - I know not to generally change a list while iterating through it, but I believe it is ok to modify other elements of a list of a list [as opposed to adding or removing entries]. For instance, in the above situation, I would like the loop to produce the following altered big list:

biglist = [[a, b, x, d], [a, b, x, d], [new_a, b, y, d], [a, b, y, d], [new_a, b, z, d], [new_a, b, x, d]]

After spending a few hours playing with an index and reading through other threads, I'm still stuck. Any help would be really appreciated.

chepner
  • 497,756
  • 71
  • 530
  • 681
jjcii
  • 139
  • 3
  • 10

3 Answers3

2

The following code achieves the outcome you desire:

biglist = [['a', 'b', 'x', 'd'],
           ['a', 'b', 'x', 'd'],
           ['a', 'b', 'y', 'd'],
           ['a', 'b', 'y', 'd'],
           ['a', 'b', 'z', 'd'],
           ['a', 'b', 'x', 'd']]

for i in range(len(biglist)):
    if i > 0:
        if biglist[i][2] != biglist[i-1][2]:
            biglist[i][0] = 'new_' + biglist[i][0]

print(biglist)

Using python 3.4.1

Leo Bontemps
  • 195
  • 1
  • 8
1

To iterate over pairs of elements I typically do this:

for x,y in zip(biglist, itertools.islice(biglist, 1, None)):
    print(x, y)

From there, you compare the third elements of the two lists and update the second list's first element if they don't match:

import itertools

biglist = [['a', 'b', 'x', 'd'], ['a', 'b', 'x', 'd'], ['a', 'b', 'y', 'd'], ['a', 'b', 'y', 'd'], ['a', 'b', 'z', 'd'], ['a', 'b', 'x', 'd']]

for x,y in zip(biglist, itertools.islice(biglist, 1, None)):
    if x[2] != y[2]:
        y[0] = 'new' + y[0]

import pprint
pprint.pprint(biglist)

Output:

[['a', 'b', 'x', 'd'],
 ['a', 'b', 'x', 'd'],
 ['newa', 'b', 'y', 'd'],
 ['a', 'b', 'y', 'd'],
 ['newa', 'b', 'z', 'd'],
 ['newa', 'b', 'x', 'd']]
Steven Kryskalla
  • 14,179
  • 2
  • 40
  • 42
0

Use two separate iterators. It's not often you create an iterator on a list explicitly, as opposed to letting a for loop create it implicitly, but here is a case where it is useful.

iter1 = iter(biglist)
iter2 = iter(biglist)
next(iter2)   # advance the second iterator

for prev, curr in itertools.izip(iter1, iter2):
    if prev[2] != curr[2]:
        curr[0] = 'new_' + curr[0]

You are correct that it is safe to modify a sublist while iterating over the outer list, because the outer list itself is not changed.

You can also use itertools.islice (as suggested by Raymond Hettinger) instead of manually consuming the first element of the second iterator.

from itertools import izip, islice
for prev, curr in izip(biglist, islice(biglist, 1, None)):
chepner
  • 497,756
  • 71
  • 530
  • 681