2

Sometimes I encounter situations where I would like to capture the match point within a comprehension, for example, in this segment:

for child1 in node1.getChildren():
    if child1.getData() in [child2.getData() for child2 in node2.getChildren()]:
        # somehow I want the list comprehension to side effect and capture child2 match point
        doNodes(child1, child2)
        # Or if we capture an index:
        doNodes(child1, node2.getChild(idx)
    else:
        doOther()

Is there a way to do this (either capture child2 or its index) without opening another loop for node2 - even using something other than compresensions.

In other words: we are just looking to shortcut the inner loop to avoid longer code and using flags to test the loop match.

Note: probably similar to this one: Finding the index of elements based on a condition using python list comprehension

Community
  • 1
  • 1
Basel Shishani
  • 7,735
  • 6
  • 50
  • 67
  • why do you not want to open another loop? you already got two loops. – gauteh Jul 30 '15 at 05:38
  • 1
    There is no “match point within a comprehension”. A list comprehension returns a list. Do you want to get the first `child2` with the same data as the `child1`? Can there be more than one? – Ry- Jul 30 '15 at 05:38
  • @minitech: we know that, but I'm just asking about a possible side effect or some other technique to avoid an inner loop. – Basel Shishani Jul 30 '15 at 05:56

2 Answers2

2

I guess you need:

for child1 in node1.getChildren():
    for child2_idx, child2 in enumerate(node2.getChildren()):
        if child1.getData() == child2.getData():
            doNodes(child1, child2_idx, child2)
            break
    else:
        doOther()

The else part will be executed when there is no break from the for loop. E.g. when the matching child2 is not found.

JuniorCompressor
  • 19,631
  • 4
  • 30
  • 57
1

How about something like -

for child1 in node1.getChildren():
    c1data, c2index = next(((child2.getData(),i) for i, child2 in enumerate(node2.getChildren()) if child2.getData() == child1.getData()) , (None,None))
    if c1data:
        # get child2 using the index above - c2index
        doNodes(child1, child2)

This returns the first index where they match.

Explanation -

  1. We create a generator function that returns the index and data for child2, where child2.getData() == child1.getData() condition is met.

  2. Then we pass that generator function into next() method and specify that if the generator does not return a next value (that is it throws StopIteration) , we should return (None, None) instead.

  3. Then We check whether the c1data is None or not. If its None that means no values matched, otherwise a value matched and the index of the match is in the variable c2index


Example/Demo -

>>> l1 = [1,2,3,4,5]
>>> l2 = [6,7,4,8,9]
>>> cd,cidx = next(((x,i) for i,x in enumerate(l2) if x == l1[3]), (None,None))
>>> cd
4
>>> cidx
2
>>> cd,cidx = next(((x,i) for i,x in enumerate(l2) if x == l1[4]), (None,None))
>>> print(cd)
None
>>> print(cidx)
None
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176