I'm taking a CSC 110 project. I am trying use dictionaries for our assignment even though we haven't learned them yet.
I have a file of countries and how many medals they won separated by new line characters. EX:
Afghanistan
0
0
0
Albania
0
0
0
Algeria
0
2
0
Each line after the country is the medals they earned starting with gold and working its way down to bronze.
I want to take these and store them in a dictionary with the structure looking something like this.
dict={Afghanistan: [0,0,0], Albania: [0,0,0]}
What I have :
olympic_stats = {}
fileIn = open('test.txt', 'r')
line = fileIn.readline()#Initialize Loop
counter = 0
while line != '':
if counter == 4:
counter = 0
if counter%4 == 0:#First Pass, COUNTRY
country_name = line.rstrip()
elif counter%4 == 1:#Second Pass, GOLD
gold_medals = int(line)
elif counter%4 == 2:#Third Pass, SILVER
silver_medals = int(line)
else: #Fourth Pass, BRONZE
bronze_medals = int(line)
#update Counter
counter += 1
if counter == 4:
olympic_stats[country_name] = [gold_medals, silver_medals, bronze_medals]
line = fileIn.readline()#Update Loop
While this works it is nasty and over complicated. I'm trying to come up with a new way to do this.
While your answer isn't super concise its not 'bad' per say. I might do something like this:
olympic_stats = {}
while line:
line_str = line.rstrip()
if line_str[0].isalpha():
country = line_str
olympic_stats[country] = []
else:
olympic_stats[country].append(line_str)
Your loop here is pretty clumsy - you can do better. You could, for example,
read the entire file at once into a list (using file.readlines())
count through the list four items at a time
which I have done here:
olympic_stats = {}
fileIn = open('test.txt', 'r')
fileLines = fileIn.readlines()
counter = 0
while counter < len(fileLines):
country_name = fileLines[counter]
gold_metals = fileLines[counter + 1]
silver_metals = fileLines[counter + 2]
bronze_metals = fileLines[counter + 3]
olympic_stats[country_name] = [gold_medals, silver_medals, bronze_medals]
counter += 4
There are more concise but much more complicated methods of doing this, by involving list comprehension and numpy or itertools, but those are more advanced topics and this should suffice for the time being.
While implementing this you might come up against errors when the number of lines in the file isn't easily divisible by four - I'll leave you to figure out how to fix that issue on your own, as it's a valuable learning experience and not too hard.
Related
my output wasn't the answer and I also had the valids list to check all the valids and I can confirm that my way of checking if something is valid is most definitely wrong, but I don't know how to fix it
the question: https://adventofcode.com/2020/day/2
my output is 450 and this is the puzzle input: https://pastebin.com/MBHaMr7m
#Day 2 part 1
count = 0
valid = 0
#valids = []
with open('inputs\input2.txt') as f:
data = f.read()
data = data.replace(" ", "")
data = data.replace("-", "")
data = data.replace(":", "")
data = [str(x) for x in data.splitlines()]
data = [list(x) for x in data]
for i in range(len(data)):
for j in data[i][3:]:
if data[i][2] == j:
count += 1
if count >= int(data[i][0]) and count <= int(data[i][1]):
valid += 1
#valids.append(data[i])
count = 0
else:
count = 0
#print(valids)
print(valid)
When I printed valids, the passwords were all invalid, my way of checking if it is correct is most likely wrong and I still can't figure out what is wrong with my code, please help.
(couldnt find a good title for the question btw)
You are making invalid assumptions about the input, in particular that each range consists of two single-digit numbers. Try something like
with open(r'inputs\input2.txt') as f:
for line in f:
lowhigh, character, password = line.strip().split()
low, high = lowhigh.split('-')
low = int(low)
high = int(high)
# Now check if <character> occurs between <low> and <high> times in <password>
def list():
list_name = []
list_name_second = []
with open('CoinCount.txt', 'r', encoding='utf-8') as csvfile:
num_lines = 0
for line in csvfile:
num_lines = num_lines + 1
i = 0
while i < num_lines:
for x in volunteers[i].name:
if x not in list_name: # l
f = 0
while f < num_lines:
addition = []
if volunteers[f].true_count == "Y":
addition.append(1)
else:
addition.append(0)
f = f + 1
if f == num_lines:
decimal = sum(addition) / len(addition)
d = decimal * 100
percentage = float("{0:.2f}".format(d))
list_name_second.append({'Name': x , 'percentage': str(percentage)})
list_name.append(x)
i = i + 1
if i == num_lines:
def sort_percentages(list_name_second):
return list_name_second.get('percentage')
print(list_name_second, end='\n\n')
above is a segment of my code, it essentially means:
If the string in nth line of names hasn't been listed already, find the percentage of accurate coins counted and then add that all to a list, then print that list.
the issue is that when I output this, the program is stuck on a while loop continuously on addition.append(1), I'm not sure why so please can you (using the code displayed) let me know how to update the code to make it run as intended, also if it helps, the first two lines of code within the txt file read:
Abena,5p,325.00,Y
Malcolm,1p,3356.00,N
this doesn't matter much but just incase you need it, I suspect that the reason it is stuck looping addition.append(1) is because the first line has a "Y" as its true_count
Here is my code I need it to read a line of text that just composes of y's a's and n's y meaning yes n meaning no a meaning abstain, I'm trying to add up the number of yes votes. The text file looks like this:
Aberdeenshire
yyynnnnynynyannnynynanynaanyna
Midlothian
nnnnynyynyanyaanynyanynnnanyna
Berwickshire
nnnnnnnnnnnnnnnnnnnnynnnnnynnnnny
here is my code:
def main():
file = open("votes.txt")
lines = file.readlines()
votes = 0
count = 0
count_all = 0
for m in range(1,len(lines),2):
line = lines[m]
for v in line:
if v == 'a':
votes += 1
elif v == 'y':
count_all += 1
count += 1
votes += 1
else:
count_all += 1
print("percentage:" + (str(count/count_all)))
print("Overall there were ", (count/count_all)," yes votes")
main()
First of all, you should note that your file.readlines() actually gives you the \n at the end of each line, which in your code will both be treated in the else block, so as no's:
>>> with open("votes.txt","r") as f:
... print(f.readlines())
...
['Aberdeenshire\n',
'yyynnnnynynyannnynynanynaanyna\n',
'Midlothian\n',
'nnnnynyynyanyaanynyanynnnanyna\n',
'Berwickshire\n',
'nnnnnnnnnnnnnnnnnnnnynnnnnynnnnny\n']
So that might explain why you don't find the good numbers...
Now, to make the code a bit more efficient, we could look into the count method of str, and maybe also get rid of those \n with a split rather than a readlines:
with open("votes.txt","r") as f:
full = f.read()
lines = full.split("\n")
votes = 0
a = 0
y = 0
n = 0
for m in range(1,len(lines),2):
line = lines[m]
votes += len(line) # I'm counting n's as well here
a += line.count("a")
y += line.count("y")
n += line.count("n")
print("Overall, there were " + str(100 * y / (y + n)) + "% yes votes.")
Hope that helped!
More or less pythonic one liner, it doesn't give you the votes for each person/city tho:
from collections import Counter
l = """Aberdeenshire
yyynnnnynynyannnynynanynaanyna
Midlothian
nnnnynyynyanyaanynyanynnnanyna
Berwickshire
nnnnnnnnnnnnnnnnnnnnynnnnnynnnnny"""
Counter([char for line in l.split('\n')[1::2] for char in line.strip()])
Returns:
Counter({'a': 11, 'n': 60, 'y': 22})
I am writing a greedy algorithm (Python 3.x.x) for a 'jewel heist'. Given a series of jewels and values, the program grabs the most valuable jewel that it can fit in it's bag without going over the bag weight limit. I've got three test cases here, and it works perfectly for two of them.
Each test case is written in the same way: first line is the bag weight limit, all lines following are tuples(weight, value).
Sample Case 1 (works):
10
3 4
2 3
1 1
Sample Case 2 (doesn't work):
575
125 3000
50 100
500 6000
25 30
Code:
def take_input(infile):
f_open = open(infile, 'r')
lines = []
for line in f_open:
lines.append(line.strip())
f_open.close()
return lines
def set_weight(weight):
bag_weight = weight
return bag_weight
def jewel_list(lines):
jewels = []
for item in lines:
jewels.append(item.split())
jewels = sorted(jewels, reverse= True)
jewel_dict = {}
for item in jewels:
jewel_dict[item[1]] = item[0]
return jewel_dict
def greedy_grab(weight_max, jewels):
#first, we get a list of values
values = []
weights = []
for keys in jewels:
weights.append(jewels[keys])
for item in jewels.keys():
values.append(item)
values = sorted(values, reverse= True)
#then, we start working
max = int(weight_max)
running = 0
i = 0
grabbed_list = []
string = ''
total_haul = 0
# pick the most valuable item first. Pick as many of them as you can.
# Then, the next, all the way through.
while running < max:
next_add = int(jewels[values[i]])
if (running + next_add) > max:
i += 1
else:
running += next_add
grabbed_list.append(values[i])
for item in grabbed_list:
total_haul += int(item)
string = "The greedy approach would steal $" + str(total_haul) + " of
jewels."
return string
infile = "JT_test2.txt"
lines = take_input(infile)
#set the bag weight with the first line from the input
bag_max = set_weight(lines[0])
#once we set bag weight, we don't need it anymore
lines.pop(0)
#generate a list of jewels in a dictionary by weight, value
value_list = jewel_list(lines)
#run the greedy approach
print(greedy_grab(bag_max, value_list))
Does anyone have any clues why it wouldn't work for case 2? Your help is greatly appreciated.
EDIT: The expected outcome for case 2 is $6130. I seem to get $6090.
Your dictionary keys are strings, not integers so they are sorted like string when you try to sort them. So you would get:
['6000', '3000', '30', '100']
instead wanted:
['6000', '3000', '100', '30']
Change this function to be like this and to have integer keys:
def jewel_list(lines):
jewels = []
for item in lines:
jewels.append(item.split())
jewels = sorted(jewels, reverse= True)
jewel_dict = {}
for item in jewels:
jewel_dict[int(item[1])] = item[0] # changed line
return jewel_dict
When you change this it will give you:
The greedy approach would steal $6130 of jewels.
In [237]: %paste
def greedy(infilepath):
with open(infilepath) as infile:
capacity = int(infile.readline().strip())
items = [map(int, line.strip().split()) for line in infile]
bag = []
items.sort(key=operator.itemgetter(0))
while capacity and items:
if items[-1][0] <= capacity:
bag.append(items[-1])
capacity -= items[-1][0]
items.pop()
return bag
## -- End pasted text --
In [238]: sum(map(operator.itemgetter(1), greedy("JT_test1.txt")))
Out[238]: 8
In [239]: sum(map(operator.itemgetter(1), greedy("JT_test2.txt")))
Out[239]: 6130
I think in this piece of code i has to be incremented on the else side too
while running < max:
next_add = int(jewels[values[i]])
if (running + next_add) > max:
i += 1
else:
running += next_add
grabbed_list.append(values[i])
i += 1 #here
this and #iblazevic's answer explains why it behaves this way
I have an input file:
3
PPP
TTT
QPQ
TQT
QTT
PQP
QQQ
TXT
PRP
I want to read this file and group these cases into proper boards.
To read the Count (no. of boards) i have code:
board = []
count =''
def readcount():
fp = open("input.txt")
for i, line in enumerate(fp):
if i == 0:
count = int(line)
break
fp.close()
But i don't have any idea of how to parse these blocks into List:
TQT
QTT
PQP
I tried using
def readboard():
fp = open('input.txt')
for c in (1, count): # To Run loop to total no. of boards available
for k in (c+1, c+3): #To group the boards into board[]
board[c].append(fp.readlines)
But its wrong way. I know basics of List but here i am not able to parse the file.
These boards are in line 2 to 4, 6 to 8 and so on. How to get them into Lists?
I want to parse these into Count and Boards so that i can process them further?
Please suggest
I don't know if I understand your desired outcome. I think you want a list of lists.
Assuming that you want boards to be:
[[data,data,data],[data,data,data],[data,data,data]], then you would need to define how to parse your input file... specifically:
line 1 is the count number
data is entered per line
boards are separated by white space.
If that is the case, this should parse your files correctly:
board = []
count = 0
currentBoard = 0
fp = open('input.txt')
for i,line in enumerate(fp.readlines()):
if i == 0:
count = int(i)
board.append([])
else:
if len(line[:-1]) == 0:
currentBoard += 1
board.append([])
else: #this has board data
board[currentBoard].append(line[:-1])
fp.close()
import pprint
pprint.pprint(board)
If my assumptions are wrong, then this can be modified to accomodate.
Personally, I would use a dictionary (or ordered dict) and get the count from len(boards):
from collections import OrderedDict
currentBoard = 0
board = {}
board[currentBoard] = []
fp = open('input.txt')
lines = fp.readlines()
fp.close()
for line in lines[1:]:
if len(line[:-1]) == 0:
currentBoard += 1
board[currentBoard] = []
else:
board[currentBoard].append(line[:-1])
count = len(board)
print(count)
import pprint
pprint.pprint(board)
If you just want to take specific line numbers and put them into a list:
line_nums = [3, 4, 5, 1]
fp = open('input.txt')
[line if i in line_nums for i, line in enumerate(fp)]
fp.close()