I have a weird problem when trying create a string when using a dictionary value. Basically, I have a function that opens a file, reads a line, and stores the values it finds in that line in a dictionary. Then, it sends those values to an external program. Here is the code:
def createLandscapes(file):
landscapeParameters = {'FILE': "NULL",
'N': "NULL",
'K': "NULL",
'NUM': "100"}
for line in file:
if line == "END LANDSCAPES\n":
break
else:
parameters = line.replace(" ", '').split(",")
for parameter in parameters:
parameter = parameter.split("=")
if parameter[0] not in landscapeParameters:
malformedFile()
landscapeParameters[parameter[0]] = parameter[1]
for key in landscapeParameters:
if landscapeParameters[key] == "NULL":
malformedFile()
# This print statment is for diagnostic purposes
print("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
landscapeParameters['N'],
landscapeParameters['K'],
landscapeParameters['NUM']))
os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters['FILE'],
landscapeParameters['N'],
landscapeParameters['K'],
landscapeParameters['NUM']))
To make this very clear, the function looks for a series of parameter inputs on a single, comma separated line, in the form of
FILE=example, N=20, K=5, NUM=100
It takes those inputs and overrides the default inputs (if specified) in landscapeParameters, and uses the values in landscapeParameters to call an external program.
The strange this is that the string formatting doesn't seem to work correctly when I use the default parameters in landscapeParameters. What I mean by this is that if the function reads the line:
FILE=example, N=20, K=5, NUM=100
Everything works correctly, and the print statement prints:
./generateScoreTables example 20 5 100
However, if the function reads the line:
FILE=example, N=20, K=5
Where I've left NUM out to use the default parameter, I get the following output instead:
./generateScoreTables testland1 15
0 100
Segmentation fault
sh: 2: 0: not found
It appears that format is not formatting this string correctly, but I don't understand why. Does anyone have any insight into this?
The problem has already been pointed out to you, but I'm still unable to comment so I'll leave this separate. This would involve reworking your code a little bit.
Once you get to this stage:
parameters = ['FILE=example', 'N=20', 'K=5', 'NUM=100']
# make a list of tuples with [(FILE, default), ('N', 20)...]
pars = [x.split("=") for x in parameters]
Now convert each twople into a Key, value pair in a dictionary dict_of_pars
dict_of_pars = {k: v for k, v in pars}
#dictionary with values for a single line
# {'FILE': 'example', 'N': '20', 'K': '5', 'NUM': '100'}
At this point you will have a dictionary containing all defined parameters for any particular line. If you make a function (that outputs) that holds default values you can send the available arguments for a line using **dict_of_pars in the call
# define output function with default parameters
def output(FILE='example, N='n', K='k', NUM='num'):
os.system(FILE, N, K, NUM)
Now you can call the function using
output(**dict_of_pars) #will unpack the arguments into output function
Made one of these temporary dictionaries for each line in the file, pass it to the output. Hope this helps.
You're updating the same variable on every loop, so if it reads one line that doesn't have a particular field it will use the value from the last time it read it.
Instead declare an empty dictionary inside the loop and use the .get function to have a default value if the key doesn't exist in the dictionary.
def createLandscapes(file):
params = ['FILE','N','K','NUM']
for line in file:
if line == "END LANDSCAPES\n":
break
else:
landscapeParameters = {}
parameters = line.replace(" ", '').split(",")
for parameter in parameters:
parameter = parameter.split("=")
if parameter[0] not in params:
malformedFile()
landscapeParameters[parameter[0]] = parameter[1]
for key in landscapeParameters:
if landscapeParameters[key] == "NULL":
malformedFile()
os.system("./generateScoreTables {} {} {} {}".format(landscapeParameters.get('FILE',''),
landscapeParameters.get('N',''),
landscapeParameters.get('K',''),
landscapeParameters.get('NUM',100)))
You'll probably need to tweak this a little bit, but it should give you more predictable results.
Related
This is what I am supposed to do in my assignment:
This function is used to create a bank dictionary. The given argument
is the filename to load. Every line in the file will look like key:
value Key is a user's name and value is an amount to update the user's
bank account with. The value should be a number, however, it is
possible that there is no value or that the value is an invalid
number.
What you will do:
Try to make a dictionary from the contents of the file.
If the key doesn't exist, create a new key:value pair.
If the key does exist, increment its value with the amount.
You should also handle cases when the value is invalid. If so, ignore that line and don't update the dictionary.
Finally, return the dictionary.
Note: All of the users in the bank file are in the user account file.
Example of the contents of 'filename' file:
Brandon: 115.5
James: 128.87
Sarah: 827.43
Patrick:'18.9
This is my code:
bank = {}
with open(filename) as f:
for line in f:
line1 = line
list1 = line1.split(": ")
if (len(list1) == 2):
key = list1[0]
value = list1[1]
is_valid = value.isnumeric()
if is_valid == True
value1 = float(value)
bank[(key)] = value1
return bank
My code returns a NoneType object which causes an error but I don't know where the code is wrong. Also, there are many other errors. How can I improve/fix the code?
Try this code and let me explain everything on it because it depends on how much you're understanding Python Data structure:
Code Syntax
adict = {}
with open("text_data.txt") as data:
"""
adict (dict): is a dictionary variable which stores the data from the iteration
process that's happening when we're separating the file syntax into 'keys' and 'values'.
We're doing that by iterate the file lines from the file and looping into them.
The `line` is each line from the func `readlines()`. Now the magic happens here,
you're playing with the line using slicing process which helps you to choose
the location of the character and play start from it. BUT,
you'll face a problem with how will you avoid the '\n' that appears at the end of each line.
you can use func `strip` to remove this character from the end of the file.
"""
adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip('\n') for line in data.readlines()}
print(adict)
Output
{' Brandon': '115.5', ' James': '128.87', ' Sarah': '827.43', ' Patrick': "'18.9"}
In term of Value Validation by little of search you will find that you can check the value if its a number or not
According to Detect whether a Python string is a number or a letter
a = 5
def is_number(a):
try:
float (a)
except ValueError:
return False
else:
return True
By Calling the function
print(is_number(a))
print(is_number(1.4))
print(is_number('hello'))
OUTPUT
True
True
False
Now, let's back to our code to edit;
All you need to do is to add condition to this dict..
adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip(' \n') for line in data.readlines() if is_number(line[line.index(':')+1: ].strip('\n')) == True}
OUTPUT
{'Brandon': '115.5', 'James': '128.87', 'Sarah': '827.43'}
You can check the value of the dict by passing it to the function that we created
Code Syntax
print(is_number(adict['Brandon']))
OUTPUT
True
You can add more extensions to the is_number() function if you want.
You're likely hitting the return in the else statement, which doesn't return anything (hence None). So as soon as there is one line in your file that does not contain 2 white-space separated values, you're returning nothing.
Also note that your code is only trying to assign a value to a key in a dictionary. It is not adding a value to an existing key if it already exists, as per the documentation.
This should effectively do the job:
bank = {}
with open(filename) as file:
for line in file:
key, val = line.rsplit(": ", 1) # This will split on the last ': ' avoiding ambiguity of semi-colons in the middle
# Using a trial and error method to convert number to float
try:
bank[key] = float(val)
except ValueError as e:
print(e)
return bank
i am trying to sort this external file but i keep getting this error and have no idea how to fix it. my code is:
with open('Leaderboard.txt', "r") as fin:
HiScores = fin.read().splitlines()
HiScoresList = []
for score in HiScores:
namescore = score.split(', ')
score = str(score.strip())
HiScoresList.append((namescore))
# Look at two score entries, and compare which score is larger
def BestScore(a, b):
return cmp(b[1], a[1])
HiScoresList.sort(key=(BestScore))
for HiScore in HiScoresList:
print(HiScore)
and this is the error
HiScoresList.sort(key=(BestScore))
TypeError: BestScore() missing 1 required positional argument: 'b'
im pretty new to python so if you could explain how to fix this in your response i would appreciate it
.sort() expects a key that takes one argument. It feeds each element in HiScoresList into that key function, and uses the output. Even if each element of HiScoresList is a tuple, that element still gets passed as only one argument.
The easy fix to make the error go away is to change BestScore() to take a 2-tuple as an argument, instead of two entire arguments:
def BestScore(tup):
a, b = tup
return cmp(b[1], a[1])
As documented, the key argument to list.sort() isn't a comparison function of two elements but a function taking one single element and returning the value to be used for sorting this element.
In your case, assuming your HiScoreList is a list of (name, score) tuples and you want to sort on the score, the key function will receive a (name, score) tuple and should return the score part, ie:
def BestScore(namescore):
return namescore[1]
now since you kept your scores as strings, this will still not work as expected (it would sort "12" before "2" - those are strings so they are sorted on lexicographical order). You can either change BestScore to take care of this:
def BestScore(namescore):
return int(namescore[1])
or turn the scores into it right from the start (which is what I would do):
hiscores = []
with open('Leaderboard.txt', "r") as fin:
for line in fin:
line = line.strip()
if not line:
continue
name, score = line.split(",", 1)
hiscores.append((name.strip(), int(score)))
hiscores.sort(key=lambda namescore: namescore[1])
print(hiscores)
I would like the first two words of a user input string to be read as function arguments for where to save the string. I've settled on using a dict instead of many if statements, but I'm not sure how to structure the dict.
I believe this is a correct start:
input: "question physics What happens to atoms when they are hit by photons?"
result: program saves the input in location questions\physics
raw_entry = input("Enter text in the following format: type subtype text")
instructions = raw_entry.split()[:2]
The two words (each being a "get_id" in the example) will designate where to save the text. This example seems to be what I'm looking for, but I'm not sure how to change it for my case.
function_dict = {'get_id':
(
# function
requests.get,
# tuple of arguments
(url + "/users/" + user,),
# dict of keyword args
{'headers': self.headers}
)
}
Let me know if I'm going about this logically or if it doesn't make sense. Thanks!
You will need to define the functions separately from the dictionary
For example:
def get_id():
... the function's code ...
function_dict = { "get_id":get_id, ... }
you can then call the function with its keyword:
function_dict["get_id"]()
but you can also do this without a dictionary if the keyword is the same as the function name:
globals()["get_id"]()
I can't seem to figure out how to write this piece of Python Code.
I need to read something in from a file, which is this:
Jake FJ49FJH
Bob FJ49GKH
I've imported the file into a dictionary. I then check if the number plate (following the names) contains the sequence of two letters, two numbers, then three letters. Here is that part of the code:
d = {} # Blank Dictionary
with open("plates.txt") as f:
d = dict(x.rstrip().split(None, 1) for x in f) # Put file into dictionary
names = d.keys()
print(names)
#carReg = ??
a,b,c = carReg[:2],carReg[2:4],carReg[4:]
if all((a.isalpha(),b.isdigit(),c.isalpha(),len(c)== 3)):
print("Valid Reg")
else:
print("Invalid Reg")
# Now get the name of the person with the invalid carReg
As you can see, I don't know what to put for carReg. I need to loop through the dictionary, like in a list when you can use an integer to get part of the list. If the program returns Invalid Reg, then I need to get the key that the invalid reg belongs to - which will be a name.
Any help appreciated.
Iterate over dict.items(); it'll give you the (key, value) pairs from the dictionary:
for name, car_registration in d.items():
so this is probably very simple but it's confusing me.
I have a function that takes in a txt file in JSON form and sorts it in descending order of bandwidth. The function is:
def sort_guards_with_input(guards):
json_source = json.dumps(guards)
data = json.loads(str(json_source))
data['relays'].sort(key=lambda item: item['bandwidth'], reverse=True)
data = json.dumps(data)
return data
segundo = sort_guards_with_input("the original txt file")
..and this returns the sorted file of the form (lets call it TEXT):
{"relays": [{"nickname": "Snowden4ever pd7wih1gdUU8bLhWsvH6QHDWfs8",
"bandwidth": 201000, "type": ["Fast", "Guard", "HSDir", "Named", "Running",
"Stable", "V2Dir", "Valid"]},{"nickname": "rmblue jMdIu0VZYE+S2oeHShQBAHsdj80",
"bandwidth": 8, "type": ["Fast", "Guard", "HSDir", "Running", "Stable", "Unnamed",
"V2Dir", "Valid"]}]}
Now I have a function that pulls out the banwidth and nickname and creates a list. The function is:
def get_sorted_names_bw(guards):
sorted_guards_bw = list(entry['bandwidth'] for entry in guards["relays"])
sorted_guards_names = list(d['nickname'] for d in guards["relays"])
temps = [None]*(len(sorted_guards_bw)+len(sorted_guards_names))
temps[::2] = sorted_guards_bw
temps[1::2] = sorted_guards_names
sorted_grds_w_names = [temps[i:i+2] for i in range(0, len(temps), 2)]
return sorted_grds_w_names
The problem is when I try and print the result of get_sorted_names_bw by doing:
print get_sorted_names_bw(segundo)
.. I get the error:
sorted_guards_bw = list(entry['bandwidth'] for entry in guards["relays"])
TypeError: string indices must be integers, not str
But if i try and print the the result of get_sorted_names_bw with copy and pasting TEXT as the argument it returns a result (the wrong one because nicknames and bandwidths are mixed up, that's another problem I'll deal with myself, unless the reader is feeling very kind and wants to help with that too :) ). Namely:
[[201000, 'rmblue jMdIu0VZYE+S2oeHShQBAHsdj80'], [8, 'Snowden4ever pd7wih1gdUU8bLhWsvH6QHDWfs8']]
Why do I get an error when I try use an argument generated by a prior function but don't get an error when I just copy and paste the argument?
Thanks and sorry for the long post.
Your function sort_guards_with_input dumps the data to a JSON string and returns that string. But get_sorted_names_bw assumes it is receiving the actual data (as a dict), not a string representation of it. The easiest thing is probably to just have sort_guards_with_input return data without dumping it to JSON. That is:
def sort_guards_with_input(guards):
json_source = json.dumps(guards)
data = json.loads(str(json_source))
data['relays'].sort(key=lambda item: item['bandwidth'], reverse=True)
return data