如何将Python中判断(i+j)%2==0的嵌套for循环简化为单循环?
Great question! Let’s break this down—your nested loop is effectively looking for all pairs (i, j) where i ranges from 0 to x-1, j ranges from 0 to y-1, and i + j is even. As you noted, this is like checking if two dice rolls sum to an even number, but with variable "sides" on each die.
The key insight here is that i + j is even if and only if i and j have the same parity (both even, or both odd). We can leverage this to collapse the nested loops into a single loop by grouping valid pairs and mapping them to a linear counter.
Option 1: Iterate by parity groups (simpler, changes traversal order)
This approach first iterates all even-even pairs, then all odd-odd pairs. It’s easier to implement and avoids tracking state between iterations.
First, calculate how many valid pairs exist in each group:
- Number of even
ivalues:even_i = (x + 1) // 2 - Number of odd
ivalues:odd_i = x // 2 - Number of even
jvalues:even_j = (y + 1) // 2 - Number of odd
jvalues:odd_j = y // 2
Then use a single loop variable to cover both groups:
# Calculate total valid pairs total_pairs = even_i * even_j + odd_i * odd_j for k in range(total_pairs): # Split into even-even and odd-odd groups even_even_count = even_i * even_j if k < even_even_count: # Map k to even i and even j i = 2 * (k // even_j) j = 2 * (k % even_j) else: # Adjust k to start from 0 for the odd-odd group k_remaining = k - even_even_count # Map k_remaining to odd i and odd j i = 2 * (k_remaining // odd_j) + 1 j = 2 * (k_remaining % odd_j) + 1 # Execute your original logic here # print(f"Valid pair: ({i}, {j})")
Option 2: Preserve original nested loop order
If you need to keep the exact traversal order of the original nested loop (i.e., iterate all valid j for i=0, then all valid j for i=1, etc.), you can use a single loop with state tracking to mimic the nested behavior:
if x == 0 or y == 0: # Edge case: no pairs to process pass current_i = 0 # Set initial j based on current_i's parity current_j = 0 if current_i % 2 == 0 else 1 # Precompute total valid pairs to know when to stop even_i = (x + 1) // 2 odd_i = x // 2 even_j = (y + 1) // 2 odd_j = y // 2 total_pairs = even_i * even_j + odd_i * odd_j for _ in range(total_pairs): # Execute your original logic here # print(f"Valid pair: ({current_i}, {current_j})") # Move to the next valid j current_j += 2 # If j is out of bounds, move to the next valid i if current_j >= y: current_i += 1 # Find the next i that has at least one valid j while current_i < x: new_j = 0 if current_i % 2 == 0 else 1 if new_j < y: current_j = new_j break current_i += 1
Why this works
Both approaches eliminate nesting by focusing on the core condition (i and j share parity) instead of iterating all possible pairs and filtering. The first approach is more efficient and readable for most cases, while the second preserves the exact order of the original nested loop if that’s required for your use case.
内容的提问来源于stack exchange,提问作者Chandrachud Pati

