Changing string to avoid duplication in a systematic manner? - python

Take the list Usernames as shown below.
Usernames = ["johnsmith"]
I have the variable NewUsername and I need to check if its value is already contained in the list. If not, an integer will be concatenated to the end of it.
Examples:
NewUsername = "alexsmith"
Usernames = ["johnsmith", "alexsmith"]
NewUsername = "johnsmith"
Usernames = ["johnsmith", "alexsmith", "johnsmith1"]
NewUsername = "johnsmith"
Usernames = ["johnsmith", "alexsmith", "johnsmith1", "johnsmith2"]
Now, I know I can do this with something like this, but it would only check for the first 'level' of duplicate names.
if NewUsername in Usernames:
NewUsername = NewUsername + "1"
Usernames.append(NewUsername)
Question: How can I handle all duplications in a similar manner?

Maybe is a bit elaborate, but you could use a custom child class of a list. To give you an idea:
from collections import Counter
class UsernameList(list):
def __init__(self, *args):
super(UsernameList, self).__init__()
self._ucount = Counter()
for e in args[0]:
self.append(e)
def append(self, el):
if isinstance(el, str):
if self._ucount[el] == 0:
super(UsernameList, self).append(el)
else:
fixel = el + str(self._ucount[el])
super(UsernameList, self).append(fixel)
self._ucount.update([fixel])
self._ucount.update([el])
else:
raise TypeError("Only string can be appended")
Now you could do:
Usernames = UsernameList(["johnsmith"]) #Username is ["johnsmith"]
Usernames.append("johnsmith") #Username becomes ["johnsmith", "johnsmith1"]
Usernames.append("johnsmith") #Username becomes ["johnsmith", "johnsmith1", "johnsmith2"]
Apart the new __init__ and append methods, UsernameList has all the methods of a list, and works exactly as a list. Don't bother about the counter attribute, it's there to keep track of the usernames inputed and add the correct number in case of repetitions.
To have something more consistent you may need to override other methods: i'm just giving you an idea, far from writing a full working code here.
You may have a look at the docs for more details on which methods you may need to override.

Related

Input from user to print out a certain instance variable in python

I have created a class with programs:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
Channel 1, start:16.00 end:17.45 viewers: 100 name: Matinee:The kiss on the cross
Channel 1, start:17.45 end:17.50 viewers: 45 name: The stock market today
Channel 2, start:16.45 end:17.50 viewers: 30 name: News
Channel 4, start:17.25 end:17.50 viewers: 10 name: Home building
Channel 5, start:15.45 end:16.50 viewers: 28 name: Reality
I also have created a nested list with the programs:
[[1,16:00, 17,45, 100, 'Matinee: The kiss on the cross'],[1,17:45, 17,50, 45,'The stock market today'],[2,16:45, 17,50, 30,'News'], [4,17:25, 17,50, 10,'Home building'],[5,15:45, 16,50, 28,'Reality']
Now we want the user to be able to write the name of a program:
News
The result should be:
News 19.45-17.50 has 30 viewers
I thought about how you could incorporate a method to avoid the program from crashing if the input is invalid/ not an instance variable
I have tried this:
Check_input():
print('Enter the name of the desired program:')
while True: #Continue asking for valid input.
try:
name = input('>')
if name == #is an instance?
return name
else:
print('Enter a program that is included in the schedule:') #input out of range
except ValueError:
print('Write a word!') #Word or letter as input
print('Try again')
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory"
Do you have any suggestions how to combat the problem?
All help is much appreciated!
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
Well if all your programs have a unique name then the easiest approach would probably be to store them in a dictionary instead of a nested list like:
programs = {
"News": Program("2", "16:45", "17:50", "News", "30", "60"),
"Reality": <Initialize Program class object for this program>,
...
}
Then you could just use the get dictionary method (it allows you to return a specific value if the key does not exist) to see if the asked program exists:
name = input('>')
program = programs.get(name, None)
if program:
print(program)
else:
# raise an exception or handle however you prefer
And if your programs don't have a unique name then you will have to iterate over the list. In which case I would probably return a list of all existing objects that have that name. A for loop would work just fine, but I would switch the nested list with a list of Program objects since you already have the class.
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory" Do you have any suggestions how to combat the problem.
I would say that the most elegant solution is to override the __str__ method of your Program class so that you can just call print(program) and write out the right output. For example:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
def __str__(self):
return self.name + " " + self.start + "-" + self.end + " has " + self.viewers + " viewers"
should print out
News 19.45-17.50 has 30 viewers
when you call it like:
program = programs.get(name, None)
if program:
print(program)

Finding class via string

import random
class Game():
def __init__(self, username, gameId):
self.users = []
self.users.append(str(username))
self.gameId = gameId
def new_user(self, username):
self.users.append(str(username))
def remove_user(self, username):
try:
self.users.remove(username)
except:
print("[-] User not found!")
def generate_gameId():
gameId = ""
letters = 5
while(letters>0):
gameId += chr(random.randint(65, 90))
letters-=1
return(gameId)
lobby = []
for i in range(2):
lobby.append(generate_gameId())
lobby[i] = Game("Test", lobby[i])
lobby[i].new_user("Test123")
lobby[i].remove_user("Test123")
This is my code for a simple networking game, I will have multiple Game classes at the same time, but I need to find the specific object of a specific gameId. The gameId is randomly generated. Each time a user wants to join the lobby he has to enter the gameId to enter.
How would you achieve something like this? Am I doing it wrong?
There are some things that can be refactored in your code:
In the constructor of your Game class, there's no need for a username parameter, since there's already a new_user method:
class Game():
def __init__(self, gameId):
# Just create the list of users
self.users = []
self.gameId = gameId
# ...
lobby = []
for i in range(2):
lobby.append(generate_gameId())
lobby[i] = Game(lobby[i])
# Use the `new_user` method to create a Test
lobby[i].new_user("Test")
lobby[i].new_user("Test123")
lobby[i].remove_user("Test123")
You're storing the ids in an integer list. You should use a dictionary given that a game will have an unique id:
lobby = {}
for i in range(2):
game_id = generate_gameId()
game = Game(game_id)
# Create a entry in the dictionary
lobby[game_id] = game
game.new_user("Test")
game.new_user("Test123")
game.remove_user("Test123")
Then, you can access the list of games and their ids:
for game_id, game in lobby.items():
print(f'The game {game_id} has the following users:')
for user in game.users:
print(user)
print()
The other guys said everything I was going to say so I deleted most of my post, but here's some other things you could improve on if you want:
You are not looking up a "Class" here. You're looking up an instance of a class, otherwise known as an object. The word "class" in programming always means "The definition of an object". Classes can be instantiated to make objects AKA instances. A good analogy is that a "class" is the blueprints for making a car, while the instance/object would be the car itself that was made using the blueprints(the class).
Don't combine naming conventions. You're combining camel case and snake case which is never a good idea, choose one or the other (python is usually snake case). Specifically, generate_gameId() should be generate_game_id(). This just makes it easier to write code without making spelling mistakes.

How to create and print the contents of a class?

I am creating a class structure in python for a city, that stores the name, country, population and language for a city, all of which are input by the user. The information shall then be printed.
I think that I may be successful in storing the information within the class structure (although this may be wrong as well), but I am unsuccessful in printing the information. Currently, I am receiving the error that int object is not subscriptable.
class User():
def _init_(self, username, password, email, numOfLogins):
User.username = username
User.password = password
User.email = email
User.numOfLogins = numOfLogins
#User Record Array Creation
def createUserArray(num , User):
UserArray = []
for x in range(num):
UserArray.append(User)
return UserArray
#User Record Array Population
def populateUserArray(num, UserArray):
for x in range(len(userArray)):
UserArray[x].username = str(input("Enter username."))
UserArray[x].password = str(input("Enter password."))
UserArray[x].email = str(input("Enter email address."))
UserArray[x].numOfLogins = int(input("Enter number of logins."))
return UserArray
#User Record Array Display
def displayUserArray(UserArray, num):
for x in range(len(userArray)):
print(UserArray[x].username, UserArray[x].password, UserArray[x].email, str(UserArray[x].numOfLogins))
#Top Level Program
numOfUsers = 3
userArray = createUserArray(numOfUsers, User)
userArray = populateUserArray(numOfUsers, userArray)
displayUserArray(numOfUsers, userArray)
The contents of the class should all be displayed at the end of the program, but at the minute my program crashes due to the error - int object is not subscriptable.
you can always implement the method : __str__(self) of an object , and then when you just print it with :
your_obj = User(...)
print your_obj
your __str__(self) will be called and you can return from it whatever you want to print.
for example:
def __self__(self):
return `this class has the following attributes: %s %s %s %s` % (self.username,self.password,self.email ,self.numOfLogins )
and this what will get print, i think it is more efficient and well coded to work like that and not creating a function that print each class attribute separately.
The cause of your error is quite simple and obvious: you defined the function as displayUserArray(UserArray, num) but call it with displayUserArray(numOfUsers, userArray) - IOW you pass the arguments in the wrong order.
This being said, almost all your code is wrong, you obviously don't get the difference between a class and instance and how to use a class to create instances. I strongly suggest you read at least the official tutorial, and check a couple other tutorial and/or example code on the topic of classes and instances.

Setting a dictionarys items to a variable

I was wondering if this would be possible, to save a dictionary item to a variable. So simply this is what I am doing. I am saving this item to a dictionary:
accounts{}
def accountcreator():
newusername = raw_input()
newpassword = raw_input()
UUID = 0
UUID += 1
accounts[newusername] = {newpassword:UUID}
Now basically I will be looping through the newusernames in a separate function:
def accounts():
username = raw_input()
for usernames in accounts:
if usernames == username:
#Not sure what to do from here on out
else:
accounts()
This is where I get confused. So if the username input equals a newusername in the accounts dictionary it will contiune on. I want it to save that newusernames password and UUID (the {newpassword:UUID} part) to a variable. So basically if the newusername equals the username input it will save the rest of thats informations (the {newpassword:UUID}) to a variable. So in the end the variable lets say accountinfo = {newpassword:UUID}. Thank you, I hope that makes sense.
There are a couple of errors in your code. First, probably a typo:
accounts = {}
Next, when you create the code, you are always resetting UUID to 0, making the increment a little pointless. Initialize UUID outside the function, like you do with accounts:
UUID = 0
def accountcreator():
newusername = raw_input()
newpassword = raw_input()
UUID += 1
accounts[newusername] = {newpassword:UUID}
Third, I'm not sure why you are mapping the password to the UUID. Likely, you want two separate fields in the user dictionary to store both:
accounts[newusername] = { 'password': newpassword, 'UUID': UUID }
Finally, the whole point of using a dictionary to map user names to information is that you don't need to iterate over the entire dictionary; you just index the dictionary with the user name. You do have to take care that you don't try to access a nonexistent key, though.
# Use a different name; accounts is already a dictionary
def get_account():
username = raw_input()
if username in accounts:
return accounts[username]
else:
print("No account for {0}".format(username))

In python, what is the fastest way to determine if a string is an email or an integer?

I'd like to be able to pull users from a database using either a supplied e-mail address or the user id (an integer). To do this, I have to detect if the supplied string is an integer, or an e-mail. Looking for the fastest way to do this. Thanks.
def __init__(self, data):
#populate class data
self._fetchInfo(data)
def _fetchInfo(self, data):
#If an email
#SELECT ... WHERE email = 'data'
#or if a user_id
#SELECT ... WHERE id = 'data'
#Fill class attributes
self._id = row['id']
self._email = row['id']
...
The canonical way to handle this in Python is to try first, ask forgiveness later:
def _fetchInfo(self, data):
try:
data=int(data)
sql='SELECT ... WHERE id = %s'
args=[data]
except ValueError:
sql='SELECT ... WHERE email = %s'
args=[data]
# This might fail, in which case, data was neither a valid integer or email address
This strategy also goes by the moniker "It is Easier to Ask for Forgiveness than Permission".
You can use the isinstance function:
if isinstance(data, int):
# it's an id
else:
# it's a string
Though personally, I'd just have two methods, fetchById and fetchByEmail to make it clear that's how it works.
You said both were strings, right? This would work, too.
if data.isdigit():
# it's an id
else:
# it's not
if '#' in data:
# email
else:
# id

Categories