Python列表元素两两对战排名:如何避免重复选取配对元素
Hey there! Let's work through this problem together. I see you're building a fun preference ranking project and got stuck on making sure you don't repeat any game/movie pairings—totally makes sense, that logic can feel a bit tangled at first.
First, Let's Break Down the Core Issues in Your Current Code
- Variable Scope Problem: In your
choose_gamesfunction, you're trying to usetwo_gamesbut never actually assign it the result ofrandom_two(game_list). That's why you hit a roadblock in theelseblock. - Loop Logic Misorder: You're checking if a random pair exists in
game_battles, but you aren't saving that pair to work with it if it's new.
Here's a Refactored Version of Your Code That Fixes These Issues
Let's start with simplifying the pair selection first—Python has a built-in way to pick two unique elements without writing a custom while loop:
import math import random # Move import to the top so it runs once my_games = ['A', 'B', 'C'] def random_two(game_list): # Use random.sample to pick 2 unique elements in one line return random.sample(game_list, 2) # Calculate total unique battles needed (n*(n-1)/2) total_battles = math.comb(len(my_games), 2) battle_num = 1 game_dict = {game: 0 for game in my_games} # Cleaner way to create score dict game_battles = [] def choose_games(game_list): global battle_num global game_dict global game_battles global total_battles # Keep generating pairs until we get an unused one while True: two_games = random_two(game_list) pair = tuple(two_games) reversed_pair = tuple(reversed(two_games)) # Check if either the pair or its reverse exists in our history if pair not in game_battles and reversed_pair not in game_battles: break # Exit loop once we have a new valid pair # Add both versions to history to prevent future repeats game_battles.append(pair) game_battles.append(reversed_pair) # Handle user input with proper validation while True: try: choice = int(input(f'Please choose game 1 - {two_games[0]}, or game 2 - {two_games[1]} (enter 1 or 2): ')) if choice in (1, 2): break else: print('Oops, you need to enter either 1 or 2!') except ValueError: print('That\'s not a number—please enter 1 or 2.') # Update the score for the chosen game chosen_game = two_games[choice - 1] print(f'You chose {chosen_game}!') game_dict[chosen_game] += 1 battle_num += 1 # Run all battles until every unique pair is covered while battle_num <= total_battles: choose_games(my_games) # Print final rankings print("\nFinal Preference Rankings:") for game, score in sorted(game_dict.items(), key=lambda x: x[1], reverse=True): print(f'{game}: {score} points')
Key Improvements Explained
- Simplified Pair Selection:
random.sample(game_list, 2)does exactly what your originalrandom_twofunction did, but in one clean line—no need for a custom while loop checking duplicates. - Proper Pair Checking: We generate a pair, check both it and its reverse against
game_battles, and only proceed if neither exists. This guarantees no repeated matchups. - Robust Input Validation: Added a
try/exceptblock to handle non-numeric inputs, plus a loop to force valid 1/2 entries before moving on. - Total Battle Tracking: Used
math.combto calculate how many unique battles we need, so we know when to stop the process automatically. - Cleaner Score Dictionary: A dictionary comprehension makes
game_dictmore readable than zipping lists together.
Why Your Original Logic Was Stuck
You were on the right track with storing pairs and their reverses, but you forgot to capture the result of random_two(game_list) into a variable inside choose_games. Without assigning two_games = random_two(game_list), the function had no idea what pair you were trying to work with!
Give this refactored code a try—it should fix the duplicate pair issue and make the whole process smoother. Let me know if you have any questions about how any part works!
内容的提问来源于stack exchange,提问作者MWallace

