Most efficient way to compare lists Python - python

How can I compare lists to one another. I am looking to compare the first - fourth digit of two lists.
I'm aware of being able to do
if list[1] == list[1]: but id assume there is a more efficient way to get it done. Thank you. I don't want to compare the lists overall, just x part of one list to x part of another
import random
import replit
import numpy
import time
number = 0
answer = 0
guesses = 0
x = 0
useranswer = []
generated = []
for i in range (0,4):
num = random.randrange(1,9)
generated.append(num)
replit.clear()
print("---------------------------------------------------------------------\nWelcome to MASTERMIND! you must guess the number that was generated!\n---------------------------------------------------------------------\n")
def useranswer():
answer = str(input("Select a 4 digit number: "))
if len(answer) != 4:
print("Invalid answer type")
time.sleep(999999999)
answer = ' '
else:
useranswer = list((str(answer)))
if useranswer == generated:
print("Good job! You became the MASTERMIND in one turn!")
else:
while useranswer != generated:
useranswer()
guesses +=1
if useranswer == generated:
print("You have become the mastermind in " + guesses + " tries!")
else:
c = numpy.intersect1d(useranswer, generated, return_indices=True)[1]
print("You got " + c + " correct! ")```

You can always use list slicing to compare the specified range of items between lists.
a = [1, 2, 3, 4, 7, 8]
b = [1, 2, 3, 4, 5, 6]
a[:3] == b[:3]
The above will yield a True if they match.
If you want to return the indexes of common elements between the two lists, there's a library called Numpy which has powerful features to do such jobs efficiently.
import numpy
a = [1, 2, 3, 4]
b = [0, 4, 6, 2]
_, c, d = numpy.intersect1d(a, b, return_indices=True)
This would return the following indexes:
print(c)
print(d)
array([0, 1, 3]
array([0, 3, 1])
But the answer to your question:
import random
import replit
import copy
import numpy
import time
number = 0
answer = 0
guesses = 0
x = 0
useranswer = []
generated = []
for i in range (0,4):
num = random.randrange(1,9)
generated.append(num)
replit.clear()
print("---------------------------------------------------------------------\nWelcome to MASTERMIND! you must guess the number that was generated!\n---------------------------------------------------------------------\n")
def useranswer_func():
answer = str(input("Select a 4 digit number: "))
if len(answer) != 4:
print("Invalid answer type")
time.sleep(9) # The time provided by you is too much to wait!
answer = ' '
else:
useranswer = list(answer)
# You need to return values to use them outside the function.
# Also your generated has int values but useranswer have str. So convert them to int or else they would never compare!
return [int(i) for i in useranswer]
if useranswer == generated:
print("Good job! You became the MASTERMIND in one turn!")
else:
while useranswer != generated:
# The returned values need to be stored in a variable.
# Never use function name and variable name same. That could cause the error that you posted in the comment!
useranswer = useranswer_func()
guesses += 1
if useranswer == generated:
print("You have become the mastermind in " + str(guesses) + " tries!")
else:
c = []
temp = copy.deepcopy(generated) # So that the change you make in temp is not reflected in generated variable too.
for i in range(len(generated)):
if generated[i] == useranswer[i]:
c.append(temp.index(temp[i]))
temp[i] = None # If your generated has repeated values, the index returned will be different or else it would be always same.
print("You got " + str(c) + " correct! ")

Related

check if a number combination is found in a list of combinations

I am creating a program in Python simulating multiplication flash cards. I've gotten pretty far but I can't figure out how to not repeat combinations of numbers. How do I check if a pair of numbers has already been presented?
from __future__ import division
from itertools import combinations
import random
amountCorrect = 0
amountMissed = 0
comb = combinations([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 2)
print("Type 0 at any time to exit and see your score.")
while True:
firstNumber = random.randint(1,12)
secondNumber = random.randint(1,12)
ans = int(input("What is " + str(firstNumber) + " x " + str(secondNumber) + ": "))
if ans == 0:
break
elif ans == firstNumber * secondNumber:
amountCorrect += 1
else:
amountMissed += 1
totalProblems = amountCorrect + amountMissed
percentCorrect = amountCorrect/totalProblems
if .9 < percentCorrect <= 1:
print("Great job, you are doing awesome!")
elif .7 <= percentCorrect <= .89:
print("You are doing well,keep it up.")
elif .5 <= percentCorrect <= .69:
print("You are half way to becoming a master.")
else:
print("Keeping practicing, you will be a master one day.")
In short, use a set to store the pairs of numbers you have already used. Here is some code. You never use combinations in your code so I removed it.
from __future__ import division
import random
amountCorrect = 0
amountMissed = 0
highestNumber = 12
print("Type 0 at any time to exit and see your score.")
used = set()
while True:
if len(used) == highestNumber ** 2:
break
while True:
firstNumber = random.randint(1,highestNumber)
secondNumber = random.randint(1,highestNumber)
pair = (firstNumber, secondNumber)
if pair not in used:
used.add(pair)
break
ans = int(input("What is " + str(firstNumber) + " x " + str(secondNumber) + ": "))
if ans == 0:
break
elif ans == firstNumber * secondNumber:
amountCorrect += 1
else:
amountMissed += 1
totalProblems = amountCorrect + amountMissed
percentCorrect = amountCorrect/totalProblems
if .9 < percentCorrect <= 1:
print("Great job, you are doing awesome!")
elif .7 <= percentCorrect <= .89:
print("You are doing well,keep it up.")
elif .5 <= percentCorrect <= .69:
print("You are half way to becoming a master.")
else:
print("Keeping practicing, you will be a master one day.")
I just created an empty set called used, and added a new inner loop. That loop test if the pair of numbers has already been used. If so, it just loops again and tries a new pair of numbers. I also added a variable to store the highest possible number, and test of the used set is full. I end the quiz if it is full. Without this, when all possibilities are tried the program will go into an infinite loop.
Note that this code will allow both 1,2 and 2,1. If you want to allow only one of those, add both (firstNumber, secondNumber) and (secondNumber, firstNumber) to the used set.

Breaking loop to return to beginning and adding further loops

first post here and fairly new to Python; I have used the search function and tried some of the suggestions there,but still struggling.
I'm making a small program that takes a set of numbers and performs simple statistical functions on those numbers without the use of any library's or statistics packages.
The user is asked to enter values and then asked what function they want to apply to the set; I want to return to the beginning when the user selects 4.
Code below - have left out the part for user selecting '4'.
I would also like the user to have a further choice and add another set of numbers, but haven't been able to do this either.
I'm aware this is probably related to indentation or my sloppy code but I'm very much a beginner.
Thanks
# Library's used
# none
# Statement to make function work
x=True
# Initial print statements
print( "Please enter a list of numbers...")
print("Enter these individually,hitting enter after each occasion...")
# Main function
while x==True:
try:
# User input
# This wouldn't be suitable for large lists
# Need something more concise
f = int(input('Enter a value: '))
g = int(input('Enter a value: '))
h = int(input('Enter a value: '))
i = int(input('Enter a value: '))
j = int(input('Enter a value: '))
k = int(input('Enter a value: '))
l = int(input('Enter a value: '))
m = int(input('Enter a value: '))
n = int(input('Enter a value: '))
o = int(input('Enter a value: '))
# Values stored here in list
list1 =[f, g, h, i, j, k, l, m, n, o]
list2 =[f, g, h, i, j, k, l, m, n, o]
x=True
# If input produces error (!=int)
except (ValueError,TypeError,IndexError):
print ("That was not a valid number. Try again...")
else:
# Variables
length_list1=len(list1) # Length
list3= [int(i) for i in list1] # Convert list elements to int
b_sort=sorted(list3) # Sorted ascending
b_select=((length_list1+1)/2) # Select the middle value
val_1=b_select-0.5 # Subtracts -0.5 from b_select
val_2=b_select+0.5 # Add's 0.5 to b_select
b_median_float=(list3[int(val_1)]+list3[int(val_2)])/2 # Selects values either side of middle value
mode=max(set(list3),key=list3.count) # Establishes a count of each int in list, largest count stored in variable.
x=True
# When the values satisfy the condition
if (list1==list2):
print("\nAll values declared")
print ("You entered",length_list1,"values","\n",list1)
print("Select a function for your list of numbers\n1.Mean\n2.Median\n3.Mode\n4.New set of numbers\n5.Exit")
# User prompted for further input
choice = input('Enter a value (1 to 5): ')
def b_median():
# If number of values are odd
if type(b_select)==float:
return b_median_float
print(b_median_float)
# If even
else:
return print(b_select)
# Variables from calculations
a=(sum(list3)/length_list1)
b= b_median()
c=mode
# Responses to user input
if (choice=='1'):
print("The mean is:",a)
choice=input('Enter a value (1 to 5): ')
if (choice== '2'):
print("The median is:",b)
choice=input('Enter a value (1 to 5): ')
if (choice== '3'):
print("The mode is:",c)
choice=input('Enter a value (1 to 5): ')
if (choice=='5'):
sys.exit()
You can do all what you want with loops.
def median(numbers):
if len(numbers) % 2 == 1:
return sorted(numbers)[int(len(numbers)/2)]
else:
half = int(len(numbers)/2)
return sum(sorted(numbers)[half-1: half+1])/2
def mode(numbers):
counts = {numbers.count(i): i for i in numbers}
return counts[max(counts.keys())]
def read():
print("Please, enter N: a length of your list.")
number_count = int(input())
print("Please, enter all of your numbers")
numbers = list()
for i in range(number_count):
numbers.append(int(input()))
return number_count, numbers
while True:
number_count, numbers = read()
while True:
print("Please, select an option:\n1 - Median\n2 - Mode\n3 - Exit\n4 - \
New numbers\n5 - Add numbers to existing list\n6 - Print your list")
option = int(input())
if option == 1:
print(median(numbers))
if option == 2:
print(mode(numbers))
if option == 3:
sys.exit()
if option == 4:
break
if option == 5:
new_number_count, new_numbers = read()
number_count += new_number_count
numbers = numbers + new_numbers
if option == 6:
print(numbers)
I have some advice for you:
Try to write your function in the beginning - it seems clearly.
Try to google and use all python capabilities.
Give more clearly names to variables.
Good luck in your endeavours.
First of all, you should define the b_median and other functions outside the loop.
Your loop works best like this, by setting the max_size variable you can ask for as many numbers as you'd like;
max_size = 100 # can be as large as you like
# Main function
while x:
try:
list1 = []
for i in range(max_size):
list1.append(int(input('Enter a value: ')))
list2 = list(list1) # copy list1 to list2; see further down why it's super important
except TypeError:
# If input produces error (!=int)
print("That was not a valid number. Try again...")
................
choice = ''
while choice != '4':
choice = input('Enter a value (1 to 5): ')
if (choice == '1'):
print("The mean is:", a)
elif (choice == '2'):
print("The median is:", b)
elif (choice == '3'):
print("The mode is:", c)
elif (choice == '5'):
sys.exit()
The While x loop
As you can notice we changed the while x==True to while x, that is because, the while-loop will loop while the expression is true, meaning you can write while True for an infinite loop. Here we kept your x variable but you can remove it and just use True directly.
 The list copy
We will there provide you a quick example of how list copy works in python, because, you will (everyone has) fall into the trap aswell.
list1 = [1, 2, 3, 4]
list2 = list1 # we made a "copy" of list1 there
print(list1) # [1, 2, 3, 4]
print(list2) # [1, 2, 3, 4]
# seems good to me so far
# Now let's update the list2 a bit
list2[0] = "I love chocolate"
print(list2) # ['I love chocolate', 2, 3, 4]
print(list1) # ['I love chocolate', 2, 3, 4]
# whyyyyyy I just changed the value in list2, not in list1 ?!
That's because in python, doing list2 = list1 will make list2 reference the same place in memory as list1, it will clone the list1.
id(list1) == id(list2) # True
# By the way, the id() function will give you the "social security number"
# of whatever you ask for. It should be unique for each element, and when
# it's not, that means those two elements are in fact one.
# That means here, that list2 is like the second name of list1, that's
# why changing one will change both.
To avoid this and make a "real" copy we use the syntax list2 = list(list1) (some other way exists).
list1 = [1, 2, 3, 4]
list2 = list(list1) # we made a copy of list1 there
id(list1) == id(list2) # False, that means the two lists are different
print(list1) # [1, 2, 3, 4]
print(list2) # [1, 2, 3, 4]
list2[0] = "I love chocolate"
print(list2) # ['I love chocolate', 2, 3, 4]
print(list1) # [1, 2, 3, 4]

Python - creating random number string without duplicates [duplicate]

This question already has answers here:
How do I create a list of random numbers without duplicates?
(21 answers)
Closed 5 years ago.
I need help with creating a random string of 4 numbers without having duplicates.
Code:
from random import randint
correct = [randint(1,8), randint(1,8), randint(1,8), randint(1,8)]
usr_guess = [0, 0, 0, 0]
usr_guess_output = []
usr_guess_output_n = []
print(correct)
Also, if you could help me get the user input without needing commas that would be great!
Full code:
from random import randint
correct = [randint(1,8), randint(1,8), randint(1,8), randint(1,8)]
usr_guess = [0, 0, 0, 0]
usr_guess_output = []
usr_guess_output_n = []
print(correct)
guesses = 0
print('Welcome to Mastermind. Guess the combination of numbers between 1 and 8. If you get the correct number and place, a \'*\' will be printed. If you get the correct number but wrong place, a \'-\' will be printed. If you get it wrong completely, a \'#\' will be printed. The position of the output does not correlate to the positions in the actual list of numbers.')
while(True):
usr_guess_output_n = []
usr_guess_output = []
correct_count = 0
guesses += 1
# try: #Makes sure that the program still works even if the user messes up the input
usr_guess = input('Guess at the numbers (separate with commas) > ').split(',') #Splits the user input into a list of integers
usr_guess = [int(x) for x in usr_guess ] #Converts all list items into integers for comparisons
print('')
i = 0
for i in range(0,4): #Iterates the lists to check for comparisons
if correct[i] == usr_guess[i]:
usr_guess_output.append('*')
correct_count += 1
elif correct[i] in usr_guess:
usr_guess_output.append('-')
else:
usr_guess_output.append('#')
if(correct_count > 3):
break
for i in usr_guess_output:
if i == '*':
usr_guess_output_n.append('*')
for i in usr_guess_output:
if i == '-':
usr_guess_output_n.append('-')
for i in usr_guess_output:
if i == '#':
usr_guess_output_n.append('#')
print(str(usr_guess_output_n).replace(',','').replace('[','').replace(']','').replace('\'',''))
# except:
# print('something went wrong. you probably input something other than an integer')
# guesses -= 1
print('\nIt took you ' + str(guesses) + ' guesses!')
input('Press enter to exit')
How about utilising a while loop?
correct = []
#list long enough?
while len(correct) < 4:
#create random number
rand_num = randint(1, 8)
#not in the list?
if rand_num not in correct:
#include in list
correct.append(rand_num)

How to make this Battleship game more user friendly in terms of values?

I have a Battleship game set up in Python, however the grid i set up ranged between 0 and 5. Meaning the first row and columns of the battleship will be (0,0) I don't want this however, as any stranded user will likely count from 1, so they'll put (1,1) or (1,2) the value 0 won't be a value they'd think to enter. How can I make my program reflect that, in a way where 1,1 is the beginning column and row not the 2nd. As the user can only enter a value between 0 and 4, 5 is represented as an invalid value and it says it's not on the grid.
So the only possible combinations are these:
Row: 0, 1, 2, 3, 4,
Column: 0, 1, 2, 3, 4
I want it to be:
Row: 1, 2, 3, 4, 5
Column 1, 2, 3, 4, 5
Here is my code:
import random
Battleship_Board = []
for x in range(0,5):
Battleship_Board.append(["O"] * 5)
def print_Battleship_Board(Battleship_Board):
for row in Battleship_Board:
print (" ".join(row))
print ("Let's play a game of Battleships!")
print_Battleship_Board(Battleship_Board)
def Random_Battleship_Board_Row(Battleship_Board):
return random.randint(0, len(Battleship_Board)-1)
def Random_Battleship_Board_Column(Battleship_Board):
return random.randint(0, len(Battleship_Board[0])-1)
Battleship_Board_Row = Random_Battleship_Board_Row(Battleship_Board)
Battleship_Board_Column = Random_Battleship_Board_Column(Battleship_Board)
print (Battleship_Board_Row)
print (Battleship_Board_Column)
for turn in range(5):
Guess_Battleship_Board_Row = int(input("Guess the X coordinate:"))
Guess_Battleship_Board_Column = int(input("Guess the Y coordinate:"))
if Guess_Battleship_Board_Row == Battleship_Board_Row and Guess_Battleship_Board_Column == Battleship_Board_Column:
print ("You sunk the battleship!")
print ("My ship was here: [" + str(Battleship_Board_Row) + "][" + str(Battleship_Board_Column) + "]")
break
else:
if turn + 1 == 5:
Battleship_Board[Guess_Battleship_Board_Row][Guess_Battleship_Board_Column] = "X"
print_Battleship_Board(Battleship_Board)
print ("Game Over")
print ("My ship was here: [" + str(Battleship_Board_Row) + "][" + str(Battleship_Board_Column) + "]")
if (Guess_Battleship_Board_Row < 0 or Guess_Battleship_Board_Row > 4) or (Guess_Battleship_Board_Column < 0 or Guess_Battleship_Board_Column > 4):
print ("The inserted value is not on the grid.")
elif(Battleship_Board[Guess_Battleship_Board_Row ][Guess_Battleship_Board_Column] == "X"):
print ("You already inserted this combination")
else:
print ("You missed my battleship")
Battleship_Board[Guess_Battleship_Board_Row][Guess_Battleship_Board_Column] = "X"
print ("Number of turns:", turn + 1,"out of 5")
print_Battleship_Board(Battleship_Board)
You can just subtract one from the user's guess, and also add a note to say that the numbers are not zero-based. Remember to check for valid input!
Guess_Battleship_Board_Row = int(input("Guess the X coordinate:")) - 1
Guess_Battleship_Board_Column = int(input("Guess the Y coordinate:")) - 1
Get the user to input their row and columns in range 1 to 5, but then subtract 1 before you place their battleship etc.
For example if they insert '5', subtract 1 then place ship etc.
Guess_Battleship_Board_Row = int(input("Guess the X coordinate:")) - 1
Guess_Battleship_Board_Column = int(input("Guess the Y coordinate:")) - 1
Looks like a great project you got going here!
There are many ways you could solve this issue so I thought I would just shoot off a few.
Ok, so all arrays start at “0” but (0, 0) kinda looks ugly I agree. The easy way would be just to create a 6, 6 array and just don't use the 0, 0 part.
The other way would be to add +1 to the array index before displaying it or -1 before accessing the array index.
So when the user types 4, 5 all you would do is (arrayA[userinput - 1], arrayB[userinput – 1]) effectively storing at 3, 4 and the user would never know.
Also as maybe a fun challenge use alphanumeric letters for rows or columns instead.(eg. 3, C)
using a switch statement or if/esle statements.
eg.
if userSelection == 'a' or userSelection == 'A'
arrayA[0] = true
(Sorry my python syntax is REALLY rusty but the concepts should still apply)
Hope that helps!

Python multiple number guessing game

I am trying to create a number guessing game with multiple numbers. The computer generates 4 random numbers between 1 and 9 and then the user has 10 chances to guess the correct numbers. I need the feedback to display as YYYY for 4 correct numbers guessed, YNNY for first and last number guessed etc. (you get the point). the code below keeps coming back saying IndexError: list index out of range.
from random import randint
guessesTaken = 0
randomNumber = []
for x in range(4):
tempNumber = randint(1, 9)
randomNumber.append(tempNumber)
Guess = []
Guess.append(list(input("Guess Number: ")))
print(randomNumber)
print(Guess)
if randomNumber[0] == Guess[0]:
print("Y")
elif randomNumber[1] == Guess[1]:
print("Y")
elif randomNumber[2] == Guess[2]:
print("Y")
elif randomNumber[3] == Guess[3]:
print("Y")
elif randomNumber[0] != Guess[0]:
print("N")
elif randomNumber[1] != Guess[1]:
print("N")
elif randomNumber[2] != Guess[2]:
print("N")
elif randomNumber[3] != Guess[3]:
print("N")
You need four guesses to match for random numbers, you can also shorted your code using a list comp:
from random import randint
guessesTaken = 0
randomNumber = []
Guess = []
for x in range(4):
tempNumber = str(randint(1, 9)) # compare string to string
randomNumber.append(tempNumber)
Guess.append(input("Guess Number: "))
print("".join(["Y" if a==b else "N" for a,b in zip(Guess,randomNumber)]))
You can also use enumerate to check elements at matching indexes:
print("".join(["Y" if randomNumber[ind]==ele else "N" for ind, ele in enumerate(Guess)]))
To give the user guesses in a loop:
from random import randint
guessesTaken = 0
randomNumber = [str(randint(1, 9)) for _ in range(4)] # create list of random nums
while guessesTaken < 10:
guesses = list(raw_input("Guess Number: ")) # create list of four digits
check = "".join(["Y" if a==b else "N" for a,b in zip(guesses,randomNumber)])
if check == "YYYY": # if check has four Y's we have a correct guess
print("Congratulations, you are correct")
break
else:
guessesTaken += 1 # else increment guess count and ask again
print(check)
Right now you're only asking the user for one guess, and appending the guess to the Guess list. So the Guess list has one element, but you're using Guess[1], Guess[2], etc., which of course results in the IndexError
I'll rearrange your code a bit, so it doesn't stray too far from what you've done.
from random import randint
guessesTaken = 0
randomNumbers = []
Guess = [] # Combine your guesses with your loop
for x in range(4):
tempNumber = randint(1, 9)
randomNumbers.append(tempNumber)
# This should be done four times too
# In Python 2, instead of this:
# Guess.append(input("Guess Number: "))
# do this:
Guess.append(int(raw_input("Guess Number: "))) # raw_input and pass to int
# in python 3, raw_input becomes input, so do this instead:
# Guess.append(int(input("Guess Number: ")))
print(randomNumbers)
print(Guess)
You can combine these in a loop to avoid the repetitive code:
if randomNumbers[0] == Guess[0]:
print("Y")
else:
print("N")
if randomNumbers[1] == Guess[1]:
print("Y")
else:
print("N")
if randomNumbers[2] == Guess[2]:
print("Y")
else:
print("N")
if randomNumbers[3] == Guess[3]:
print("Y")
else:
print("N")
Perhaps, to print your desired result e.g. YNNY, like this:
result = []
for index in range(4):
if randomNumbers[index] == Guess[index]:
result.append("Y")
else:
result.append("N")
print(''.join(result))
If you want terser code use Python's ternary operation:
result = []
for index in range(4):
result.append("Y" if randomNumbers[index] == Guess[index] else "N")
print(''.join(result))
Or use the fact that True == 1 and False == 0 as indexes:
result = []
for index in range(4):
result.append("NY"[randomNumbers[index] == Guess[index]])
print(''.join(result))

Categories