I would like to reduce my code and eliminate 3 if statements by joining together, in an if statement, 2 variables that if printed would create the name pointing to a 3rd variable.
Currently I have 3 if statements that look like this:
if prd.lower() not in retentions_log:
I would like to use something like:
if prd.lower() not in retentions_+prd.lower:
So every time the function is called It would construct the 3rd variable
retentions+prd.lower = retentnions_log
This is one of the functions:
retentinon_approval_log = "SOME_VALUE"
def ret_handler_log(roletype, prd, pth, fnm, location):# [retention_proc]
"""Processors. 4Writing results to file."""
if prd in retentinon_approval_log:
if approval_check(roletype, prd, pth) == False:
try:
results_o.write("some_text")
except Exception as e:
print(e)
pass
else:
yaml_dumper(roletype, prd, location)
results_o.write("some_text")
else:
yaml_dumper(roletype, prd, location)
Update I'd like to be able to construct "retentinon_approval_+prd"
retentions approval being simple text and prd being "log". To
construct a variable "retentinon_approval_log" that points to "some
text" and dynamically generate this with different values that are
being passed to this function
You may use a dictionary to build variables. Example.
d={'var1':10, 'var2':20}
d['var1'+'var2'] = d['var1'] + d['var2'] #{'var1': 10, 'var2': 20, 'var1var2': 30}
I have an array of object of class Person like the below, with thisRate first set to None:
class Person(object):
def __init__(self, id, name):
self.id = id
self.name = name
self.thisRate= None
I loaded around 21K Person objects into an array, name not sorted.
Then I loaded another array from data in a file which has data for thisRate, about 13K of them, name is not sorted as well:
person_data = []
# read from file
row['name'] = 'Peter'
row['thisRate'] = '0.12334'
person_data.append(row)
Now with these 2 sets of arrays, when the name is matched between them, I will assign thisRate from person_data into Person.thisRate.
What I am doing is a loop is like this:
for person in persons:
data = None
try:
data = next(personData for personData in person_data
if personData['name'] == person.name)
except StopIteration:
print("No rate for this person: {}".format(person.name))
if data:
person.thisRate = float( data['thisRate'] )
This loop
data = next(personData for personData in person_data
if personData['name'] == person.name)
is running fine and uses 21 seconds on my machine with Python 2.7.13.
My question is, is there a faster or better way to achieve the same thing with the 2 arrays I have?
Yes. Make an dictionary from name to thisRate:
nd = {}
with open(<whatever>) as f:
reader = csv.DictReader(<whatever>):
for row in reader:
nd[row['name']] = row['thisRate']
Now, use this dictionary to do a single pass over your Person list:
for person in persons:
thisRate = nd.get(person.name, None)
person.thisRate = thisRate
if thisRate is None:
print("No rate for this person: {}".format(person.name))
Dictionaries have a .get method which allows you to provide a default value in case the key is not in the dict. I used None (which is actually what is the default default value) but you can use whatever you want.
This is a linear-time solution. Your solution was quadratic time, because you are essentially doing:
for person in persons:
for data in person_data:
if data['name'] == person.name:
person.thisRate = data['thisRate']
break
else:
print("No rate for this person: {}".format(person.name))
Just in a fashion that obscures this fundamentally nested for-loop inside of a generator expression (not really a good use-case for a generator expression, you should have just used a for-loop to begin with, then you don't have to deal with try-catch a StopIteration
I am not sure how to word the question title.
a = "Alpha";
b = "Bravo";
c = "Charlie";
fn = input("What is your first name: ")
for fletter in fn.split():
fl = fletter[0]
The code above gets the first letter entered. The goal is to then get the first letter to possible check in a while loop to see if the value of fl = one of the starting strings. Is that possible to do? Tips on where to begin?
Solution 1 [Using a dictionary]
Also makes things much simpler.
In this case, instead of defining separate variables for each string, you store them in a dictionary. So for example, instead of this:
a = "Alpha"
b = "Bravo"
c = "Charlie"
You would have this:
letterwords = {"a":"Alpha", "b":"Bravo", "c":"Charlie"}
This works very similarly to a list, however instead of indexing the dictionary you would reference to separate objects inside a dictionary according to its key. So if the dictionary letterwords is defined as above, you would reference to the string Alpha by calling letterwords["a"]. Therefore, in this case, the code would look something like this:
letterwords = {"a":"Alpha", "b":"Bravo", "c":"Charlie"}
fn = input("Please enter your first name: ")
try:
letterwords[fn[0]]
except KeyError:
print("There is no matching variable with that letter in the database.")
Solution 2 [Using the eval() function]
Not recommended.
This is perfectly possible, with the eval function. However, you should be aware that this is a quite dangerous function to run, as malicious users can use this to control the console. (Especially if you imported os.) However, it should get you over the hump for now. Here's the code:
a = "Alpha"
b = "Bravo"
c = "Charlie"
fl = input("Please enter your first name: ")
try:
compared = eval(fl[0])
except NameError:
print("Your first name's first letter does not match any strings in the database.")
More information on the eval() function here: https://docs.python.org/3/library/functions.html#eval
Hope this helped!
I am trying to write a routine to read values from a text file, (names and scores) and then be able to sort the values az by name, highest to lowest etc. I am able to sort the data but only by the position in the string, which is no good where names are different lengths. This is the code I have written so far:
ClassChoice = input("Please choose a class to analyse Class 1 = 1, Class 2 = 2")
if ClassChoice == "1":
Classfile = open("Class1.txt",'r')
else:
Classfile = open("Class2.txt",'r')
ClassList = [line.strip() for line in Classfile]
ClassList.sort(key=lambda s: s[x])
print(ClassList)
This is an example of one of the data files (Each piece of data is on a separate line):
Bob,8,7,5
Fred,10,9,9
Jane,7,8,9
Anne,6,4,8
Maddy,8,5,5
Jim, 4,6,5
Mike,3,6,5
Jess,8,8,6
Dave,4,3,8
Ed,3,3,4
I can sort on the name, but not on score 1, 2 or 3. Something obvious probably but I have not been able to find an example that works in the same way.
Thanks
How about something like this?
indexToSortOn = 0 # will sort on the first integer value of each line
classChoice = ""
while not classChoice.isdigit():
classChoice = raw_input("Please choose a class to analyse (Class 1 = 1, Class 2 = 2) ")
classFile = "Class%s.txt" % classChoice
with open(classFile, 'r') as fileObj:
classList = [line.strip() for line in fileObj]
classList.sort(key=lambda s: int(s.split(",")[indexToSortOn+1]))
print(classList)
The key is to specify in the key function that you pass in what part of each string (the line) you want to be sorting on:
classList.sort(key=lambda s: int(s.split(",")[indexToSortOn+1]))
The cast to an integer is important as it ensures the sort is numeric instead of alphanumeric (e.g. 100 > 2, but "100" < "2")
I think I understand what you are asking. I am not a sort expert, but here goes:
Assuming you would like the ability to sort the lines by either the name, the first int, second int or third int, you have to realize that when you are creating the list, you aren't creating a two dimensional list, but a list of strings. Due to this, you may wish to consider changing your lambda to something more like this:
ClassList.sort(key=lambda s: str(s).split(',')[x])
This assumes that the x is defined as one of the fields in the line with possible values 0-3.
The one issue I see with this is that list.sort() may sort Fred's score of 10 as being less than 2 but greater than 0 (I seem to remember this being how sort worked on ints, but I might be mistaken).
I have a list consisting of tuples in Python. I need to reference each index of each tuple to create a list of NBA player statics. The first index [0] in the tuple is the efficiency rating and the next two positions are the player name and lastly the team name. Right now the tuples are in a long list. When I run the program, all I get is an output of the first four tuples and not a list of the various tuples. I have tried to use append, but that did not help either.
Here is my code:
def get_data_list (file_name):
data_file = open(file_name, "r")
data = []
player_list=[]
for line_str in data_file:
# strip end-of-line, split on commas, and append items to list
data_list =line_str.strip().split(',')
data_list.append (data)
gp=int(data_list[6])
mins=int(data_list[7])
pts=int(data_list[8])
oreb=int(data_list[9])
dreb=int(data_list[10])
reb=int(data_list[11])
asts=int(data_list[12])
stl=int(data_list[13])
blk=int(data_list[14])
to=int(data_list[15])
pf=int(data_list[16])
fga=int(data_list[17])
fgm=int(data_list[18])
fta=int(data_list[19])
ftm=int(data_list[20])
tpa=int(data_list[21])
tpm=int(data_list[22])
efficiency = ((pts+reb+asts+stl+blk)-(fgm-ftm-to))/gp
data_list.append (efficiency)
data.append(data_list)
score=data_list[24]
first_name=data_list[2]
last_name=data_list[3]
team_name=data_list[4]
player_tuple = score, last_name, first_name, team_name
player_list.append(player_tuple)
a=sorted(player_list)
a.reverse()
return a
def print_results (lst):
"""Print the result in a nice format"""
print("The top 50 players based on efficiency are: ")
print('*'*75)
print('{:<20s}{:<20s}, {:<15s}{:<5s}'.format(lst[(0)],lst[(1)],lst[(2)],lst[(3)]))
file_name1 = input("File name: ")
result_list = get_data_list (file_name1)
top_50_list=[]
top_50_list=result_list[:50]
print_results(top_50_list)
I think my problem is in the print_results function.
Please remember that I am taking an intro class so many of the advanced options are not an option for me. Please keep the solutions simple.
Boliver
It looks like your problem is with the append function...
a=[some,list]
a.append(42) #a = [some,list,42]
a.append([1,2]) #now a = [some,list,42,[1,2]]
For you index 0 is itself an empty list
So in your code, for the first iteration of the loop:
data_list =line_str.strip().split(',') # data_list = [some,list]
data_list.append (data) # data_list = [some,list,[]]
...
data_list.append (efficiency) # data_list = [some,list,[],efficiency]
data.append(data_list) # data = [[some,list,[],efficiency]]
...
a = something special
The loop then continues on until the last line of the input file
Then you return a. a is only returned once and is screwy because of the before mentioned shuffling.
Play with for loops and append a bit and you should work it out no problem.
And if you are feeling brave then look up yield. A generator would be perfect here
in print_results
def print_results (lst):
"""Print the result in a nice format"""
print("The top 50 players based on efficiency are: ")
print('*'*75)
print('{:<20s}{:<20s}, {:<15s}{:<5s}'.format(lst[(0)],lst[(1)],lst[(2)],lst[(3)]))
could be somethign like
def print_results(lst):
"""Print the result in a nice format"""
print("The top 50 players based on efficiency are: ")
print('*'*75)
for player_tuple in lst:
print('{:<20s}{:<20s}, {:<15s}{:<5s}'.format(*player_tuple[:4]))
Since you have a list of tuples, each tuple representing a player, loop through each player and print out their information
I don't understand what your code is trying to do with data vs. data_list. I rewrote it to get rid of data. Also, after you compute efficiency you append it to the list, but then you seem to be pulling it off the list again as score. I simply got rid of that.
For working with files, best practice is to use a with statement so I rewrote to do that.
Also, you are converting string items to integer one at a time, when you could do them all in one go with a list comprehension. I hope list comprehensions are not a problem for you to use, because they make the code cleaner. The first list comprehension calls the .strip() method function on each of the three strings for names. The second one converts all the integers in one convenient way.
Instead of making a temp list named a and then reversing that list, I just specified the reverse=True option in sorted(). Now the list is built in reverse order, just what you want.
As others have noted, your print function needs a loop to print things in the list. Since the message in the print function says it prints the top 50, I changed the list slicing to happen inside the print function. Now the print function takes an optional argument specifying how many items to print; it has a default value of 50, so if you don't specify another value, it prints the top 50 items.
While you don't need to do it, there is a common Python feature of putting if __name__ == __main__: before your code. You can see an explanation here: What does if __name__ == "__main__": do?
def get_data_list (file_name):
player_list=[]
with open(file_name, "r") as f:
for line in f:
# split line on commas, and convert items to integer values
# make a list of the integer values.
items = line.split(',')
first_name = items[2].strip()
last_name = items[3].strip()
team_name = items[4].strip()
data_list = [int(x) for x in items[6:]
gp = data_list[0]
mins = data_list[1]
pts = data_list[2]
oreb = data_list[3]
dreb = data_list[4]
reb = data_list[5]
asts = data_list[6]
stl = data_list[7]
blk = data_list[8]
to = data_list[9]
pf = data_list[10]
fga = data_list[11]
fgm = data_list[12]
fta = data_list[13]
ftm = data_list[14]
tpa = data_list[15]
tpm = data_list[16]
efficiency = ((pts+reb+asts+stl+blk)-(fgm-ftm-to))/gp
player_tuple = efficiency, last_name, first_name, team_name
player_list.append(player_tuple)
return sorted(player_list, reverse=True)
def print_results(lst, how_many=50):
"""Print the result in a nice format"""
template = '{:<20}{:<20s}, {:<15s}{:<5s}'
print("The top {} players based on efficiency are: ".format(how_many))
print('*'*75)
for tup in lst[:how_many]:
print(template.format(tup[0], tup[1], tup[2], tup[3]))
if __name__ == "__main__":
file_name1 = input("File name: ")
result_list = get_data_list(file_name1)
print_results(result_list)
Now I'm going to smooth it out even further. This is using more advanced features in Python, but they are features that make things more convenient, not things that are just tricky.
First, instead of building a list with a list comprehension, and then picking items by index number, we will use a generator expression and directly unpack the items into variable names. A generator expression is just like a list comprehension, except that instead of building a list, it provides an "iterator" that can be looped over, or can be unpacked into variable names as I show here.
Second, in the print function, we just want to print all the values in the tuple, in order. Python provides a shortcut: putting a * in front of the tuple inside the call to .format() means "unpack this and use the unpacked values as the arguments to this function call".
def get_data_list (file_name):
player_list=[]
with open(file_name, "r") as f:
for line in f:
# Split line on commas and convert each item to integer. Unpack
# values directly into variable names. We are using a
# generator expression to convert all the items to integer,
# and Python's ability to unpack an iterator into a tuple.
items = line.strip().split(',')
# use list slicing to select just the three string values
first_name, last_name, team_name = (s.strip() for s in items[2:5])
# Use a generator expression to convert all values to int.
# Unpack directly to variable names using tuple unpacking.
# Put parentheses so Python won't worry about multiple lines
# of variable names.
(
gp, mins, pts, oreb, dreb, reb, asts,
stl, blk, to, pf, fga, fgm, fta, ftm,
tpa, tpm
) = (int(x) for x in items[6:])
efficiency = ((pts+reb+asts+stl+blk)-(fgm-ftm-to))/gp
player_tuple = efficiency, last_name, first_name, team_name
player_list.append(player_tuple)
return sorted(player_list, reverse=True)
def print_results(lst, how_many=50):
"""Print the result in a nice format"""
template = "{:<20}{:<20s}, {:<15s}{:<5s}"
print("The top {} players based on efficiency are: ".format(how_many))
print('*'*75)
for player_tuple in lst[:how_many]:
print(template.format(*player_tuple))
if __name__ == "__main__":
file_name1 = input("File name: ")
result_list = get_data_list(file_name1)
print_results(result_list)
EDIT: And here is another edited version. This one splits out the logic for parsing a line into a player_tuple into its own function. This makes get_data_list() very short.
def player_tuple(line):
# Split line on commas and convert each item to integer. Unpack
# values directly into variable names. We are using a
# generator expression to convert all the items to integer,
# and Python's ability to unpack an iterator into a tuple.
items = line.strip().split(',')
# use list slicing to select just the three string values
first_name, last_name, team_name = (s.strip() for s in items[2:5])
# use a generator expression to convert all values to int
# unpack directly to variable names using tuple unpacking
(
gp, mins, pts, oreb, dreb, reb, asts,
stl, blk, to, pf, fga, fgm, fta, ftm,
tpa, tpm
) = (int(x) for x in items[6:])
efficiency = ((pts+reb+asts+stl+blk)-(fgm-ftm-to))/gp
return efficiency, last_name, first_name, team_name
def get_data_list(file_name):
with open(file_name, "r") as f:
player_list = [player_tuple(line) for line in f]
return sorted(player_list, reverse=True)
def print_results(lst, how_many=50):
"""Print the result in a nice format"""
template = "{:<20}{:<20s}, {:<15s}{:<5s}"
print("The top {} players based on efficiency are: ".format(how_many))
print('*'*75)
for player_tuple in lst[:how_many]:
print(template.format(*player_tuple))
if __name__ == "__main__":
file_name1 = input("File name: ")
result_list = get_data_list(file_name1)
print_results(result_list)
Now that we have player_tuple() as a function, we could simplify get_data_list() even further. I won't repeat the whole program, just the simplified get_data_list(). This is probably the code I would write if I had to solve this problem.
def get_data_list(file_name):
with open(file_name, "r") as f:
return sorted((player_tuple(line) for line in f), reverse=True)
Here we don't even explicitly build the list. We just make a generator expression that provides all the player_tuple values, and directly pass that to sorted(). There is no need for this list to be given a name inside get_data_list(); it can just be built and returned in one line.