For some reason my code refuses to convert to uppercase and I cant figure out why. Im trying to then write the dictionary to a file with the uppercase dictionary values being inputted into a sort of template file.
#!/usr/bin/env python3
import fileinput
from collections import Counter
#take every word from a file and put into dictionary
newDict = {}
dict2 = {}
with open('words.txt', 'r') as f:
for line in f:
k,v = line.strip().split(' ')
newDict[k.strip()] = v.strip()
print(newDict)
choice = input('Enter 1 for all uppercase keys or 2 for all lowercase, 3 for capitalized case or 0 for unchanged \n')
print("Your choice was " + choice)
if choice == 1:
for k,v in newDict.items():
newDict.update({k.upper(): v.upper()})
if choice == 2:
for k,v in newDict.items():
dict2.update({k.lower(): v})
#find keys and replace with word
print(newDict)
with open("tester.txt", "rt") as fin:
with open("outwords.txt", "wt") as fout:
for line in fin:
fout.write(line.replace('{PETNAME}', str(newDict['PETNAME:'])))
fout.write(line.replace('{ACTIVITY}', str(newDict['ACTIVITY:'])))
myfile = open("outwords.txt")
txt = myfile.read()
print(txt)
myfile.close()
In python 3 you cannot do that:
for k,v in newDict.items():
newDict.update({k.upper(): v.upper()})
because it changes the dictionary while iterating over it and python doesn't allow that (It doesn't happen with python 2 because items() used to return a copy of the elements as a list). Besides, even if it worked, it would keep the old keys (also: it's very slow to create a dictionary at each iteration...)
Instead, rebuild your dict in a dict comprehension:
newDict = {k.upper():v.upper() for k,v in newDict.items()}
You should not change dictionary items as you iterate over them. The docs state:
Iterating views while adding or deleting entries in the dictionary may
raise a RuntimeError or fail to iterate over all entries.
One way to update your dictionary as required is to pop values and reassign in a for loop. For example:
d = {'abc': 'xyz', 'def': 'uvw', 'ghi': 'rst'}
for k, v in d.items():
d[k.upper()] = d.pop(k).upper()
print(d)
{'ABC': 'XYZ', 'DEF': 'UVW', 'GHI': 'RST'}
An alternative is a dictionary comprehension, as shown by #Jean-FrançoisFabre.
Related
File contains student ID and ID of the solved problem.
Example:
1,2
1,4
1,3
2,1
2,2
2,3
2,4
The task is to write a function which will take a filename as an argument and return a dictionary with a student ID and amount of solved tasks.
Example output:
{1:3, 2:4}
My code which doesn't support the correct output. Please, help me find a mistake and a solution.
import collections
def solved_tasks(filename):
with open(filename) as f:
for line in f.readlines():
key,value = line.strip().split(',')
dictionary = {key: collections.Counter(str(value))}
return dictionary
Since you only care about the sum, not the individual exercises, you can use a Counter on the first column:
def solved_tasks(filename):
with open(filename) as in_stream:
counts = collections.Counter(
line.partition(',')[0] # first column ...
for line in in_stream if line # ... of every non-empty row
)
return {int(key): value for key, value in counts.items()}
Assuming that you want to save the repeated instances of student id, you can use a defaultdict and save the problems solved by each student as a list in your dictionary:
import collections
dictionary = collections.defaultdict(list)
def solved_tasks(filename):
with open(filename) as f:
for line in f.readlines():
key,value = line.strip().split(',')
dictionary[key].append(value)
return dictionary
Output:
defaultdict(<type 'list'>, {'1': ['2', '4', '3'], '2': ['1', '2', '3', '4']})
If you want the sum:
def solved_tasks(filename):
with open(filename) as f:
for line in f.readlines():
key,value = line.strip().split(',')
dictionary[key] += 1
return dictionary
Output:
defaultdict(<type 'int'>, {'1': 3, '2': 4})
you can count how often a key appears
marks = """1,2
"1,4
"1,3
"2,1
"2,2
"2,3
"2,4
"2,4"""
dict = {}
for line in marks.split("\n"):
key,value = line.strip().split(",")
dict[key] = dict.get(key,[]) + [value]
for key in dict:
dict[key] = len(set(dict[key])) # eliminate duplicates
the dict.get(key,[]) method returns an empty list if the key doesn't exist in the dict as a default parameter.
#Edit: You said there may contain duplicates. This method would eliminate all duplicates.
#Edit: Added multilines with """
def solved_tasks(filename):
res = {}
values=""
with open(filename, "r") as f:
for line in f.readlines():
values += line.strip()[0] #take only the first value and concatinate with the values string
value = values[0] #take the first value
res[int(value)] = values.count(value) #put it in the dict
for i in values: #loop the values
if i != value: # if the value is not the first value, then the value is the new found value
value = i
res[int(value)] = values.count(value) #add the new value to the dict
return res
I have a text file and its content is something like this:
A:3
B:5
C:7
A:8
C:6
I need to print:
A numbers: 3, 8
B numbers: 5
C numbers: 7, 6
I'm a beginner so if you could give some help I would appreciate it. I have made a dictionary but that's pretty much all I know.
You could use an approach that keeps the values in a dictionary:
d = {} # create an empty dictionary
for line in open(filename): # opens the file
k, v = line.split(':') # unpack each line in the char before : and after
if k in d: # add the values to the dictionary
d[k].append(v)
else:
d[k] = [v]
This gives you a dictionary containing your file in a format that you can utilize to get the desired output:
for key, values in sorted(d.items()):
print(key, 'numbers:' ', '.join(values))
The sorted is required because dictionaries are unordered.
Note that using collections.defaultdict instead of a normal dict could simplify the approach somewhat. The:
d = {}
...
if k in d: # add the values to the dictionary
d[k].append(v)
else:
d[k] = [v]
could then be replaced by:
from collections import defaultdict
d = defaultdict(list)
...
d[k].append(v)
Short version (Which should sort in alphabetic order)
d = {}
lines = [line.rstrip('\n') for line in open('filename.txt')]
[d.setdefault(line[0], []).append(line[2]) for line in lines]
[print(key, 'numbers:', ', '.join(values)) for key,values in sorted(d.items())]
Or if you want to maintain the order as they appear in file (file order)
from collections import OrderedDict
d = OrderedDict() # Empty dict
lines = [line.rstrip('\n') for line in open('filename.txt')] # Get the lines
[d.setdefault(line[0], []).append(line[2]) for line in lines] # Add lines to dictionary
[print(key, 'numbers:', ', '.join(values)) for key,values in d.items()] # Print lines
Tested with Python 3.5.
You can treat your file as csv (comma separated value) so you can use the csv module to parse the file in one line. Then use defaultdict with input in the costructor the class list to say that to create it when the key not exists. Then use OrderedDict class because standard dictionary don't keeps the order of your keys.
import csv
from collection import defaultdict, OrderedDict
values = list(csv.reader(open('your_file_name'), delimiter=":")) #[['A', '3'], ['B', '5'], ['C', '7'], ['A', '8'], ['C', '6']]
dct_values = defaultdict(list)
for k, v in values:
dct_values[k].append(v)
dct_values = OrderedDict(sorted(dct_values.items()))
Then you can simply print iterating the dictionary.
A very easy way to group by key is by external library, if you are interested try PyFunctional
I have a files scores that looks like:
z:100
a:50
c:75
a:-20
c:45
a:10
c:20
z:10
z:-50
I want to return a dictionary with the key being the letter and the value being he sum of the value that letter has in the file. I am unsure how to keep a sum going while using this method.
I have
a = {key: value for (key,value) in [line.strip().split(":") for line in open("scores.txt","r")]}
print a
I'd advise against cramming everything into one line here. You can do something like this (using collections.defaultdict):
from collections import defaultdict
counts = defaultdict(int)
with open('scores.txt', 'r') as f:
for line in f:
name, score = line.strip().split(':')
d[name] += int(score)
Are you sure you want a "one-line" dictionary comprehension?
from itertools import imap, groupby
from operator import methodcaller, itemgetter
a = { k : sum(int(v[1]) for v in v_itr)
for k, v_itr in groupby(sorted(imap(methodcaller("split", ":"),
imap(methodcaller("rstrip"),
open("scores.txt", "r"))),
key=itemgetter(0)), itemgetter(0)) }
(This is not a recommendation to actually use this code; use the loop in arshajii's answer.)
A slightly easier-to-read version that uses a generator expression instead of nested calls to imap.
a = { k : sum(int(v[1]) for v in v_itr)
for k, v_itr in groupby(sorted(line.rstrip().split(":")
for line in open("scores.txt", "r"),
key=itemgetter(0)), itemgetter(0)) }
This question already has answers here:
Writing a CSV horizontally
(2 answers)
Closed 8 years ago.
Thanks to this other thread, I've successfully written my dictionary to a csv as a beginner using Python:
Writing a dictionary to a csv file with one line for every 'key: value'
dict1 = {0 : 24.7548, 1: 34.2422, 2: 19.3290}
csv looks like this:
0 24.7548
1 34.2422
2 19.3290
Now, i'm wondering what would be the best approach to organize several dictionaries with the same keys. I'm looking to have the keys as a first column, then the dict values in columns after that, all with a first row to distinguish the columns by dictionary names.
Sure, there are a lot of threads trying to do similar things, such as: Trouble writing a dictionary to csv with keys as headers and values as columns, but don't have my data structured in the same way (yet…). Maybe the dictionaries must be merged first.
dict2 = {0 : 13.422, 1 : 9.2308, 2 : 20.132}
dict3 = {0 : 32.2422, 1 : 23.342, 2 : 32.424}
My ideal output:
ID dict1 dict2 dict3
0 24.7548 13.422 32.2422
1 34.2422 9.2308 23.342
2 19.3290 20.132 32.424
I'm not sure, yet, how the column name ID for key names will work its way in there.
Use the csv module and list comprehension:
import csv
dict1 = {0: 33.422, 1: 39.2308, 2: 30.132}
dict2 = {0: 42.2422, 1: 43.342, 2: 42.424}
dict3 = {0: 13.422, 1: 9.2308, 2: 20.132}
dict4 = {0: 32.2422, 1: 23.342, 2: 32.424}
dicts = dict1, dict2, dict3, dict4
with open('my_data.csv', 'wb') as ofile:
writer = csv.writer(ofile, delimiter='\t')
writer.writerow(['ID', 'dict1', 'dict2', 'dict3', 'dict4'])
for key in dict1.iterkeys():
writer.writerow([key] + [d[key] for d in dicts])
Note that dictionaries is unordered by default, so if you want the keys in ascending order, you have to sort the keys:
for key in sorted(dict1.iterkeys(), key=lambda x: int(x)):
writer.writerow([key] + [d[key] for d in dicts])
If you need to handle situations where you can't be sure that all dicts have the same keys, you'll need to change some small stuff:
with open('my_data.csv', 'wb') as ofile:
writer = csv.writer(ofile, delimiter='\t')
writer.writerow(['ID', 'dict1', 'dict2', 'dict3', 'dict4'])
keys = set(d.keys() for d in dicts)
for key in keys:
writer.writerow([key] + [d.get(key, None) for d in dicts])
Use defaultdict(list)
from collections import defaultdict
merged_dict = defaultdict(list)
dict_list = [dict1, dict2, dict3]
for dict in dict_list:
for k, v in dict.items():
merged_dict[k].append(v)
This is what you get:
{0: [24.7548, 13.422, 32.2422], 1: [34.2422, 9.2308, 23.342], 2: [19.329, 20.132, 32.424]})
Then write the merged_dict to csv file as you had previously done for a single dict. This time writerow method of csv module will be helpful.
Here is one way to do it.
my_dicts = [dict1, dict2, dict3]
dict_names = range(1, len(my_dicts)+1)
header = "ID," + ",".join(map(lambda x: "dict"+str(x)), dict_names) + "\n"
all_possible_keys = set(reduce(lambda x,y: x + y.keys(), my_dicts, []))
with open("file_to_write.csv", "w") as output_file:
output_file.write(header)
for k in all_possible_keys:
print_str = "{},".format(k)
for d in my_dicts:
print_str += "{},".format(d.get(k, None))
print_str += "\n"
output_file.write(print_str)
It has been some time since I used Python, but here's my suggestion.
In Python, dictionary values can be of any type (as far as I remember, don't flame me if I'm wrong). At least it should be possible to map your keys to lists.
So you can loop over your dictionaries and maybe create a new dictionary 'd', and for each key, if the value is already in 'd', push the value to the value of 'd' (since the value of the associated key is a list).
Then you can write out the new dictionary as: (pseudocode)
for each key,value in dictionary
write key
write TAB
for each v in value
write v + TAB
write new line
end for
This doesn't include the 'header names' though, but I'm sure that's quite easy to add.
I have a text file with eight names, sorted by name, like this:
Anna
David
Dennis
Morgan
Lana
Peter
Joanna
Karen
And now I want to put them into a dictionary and add different keys to each of the name.
The names are on new lines. What I want to add to the names in the dict, are different binary numbers from 000-111.
How can I do this?
I have tried stuff like this:
with open ('tennis.txt', 'r') as f:
for line in f:
dict={}
for line in open('file.txt'):
bin[0]=next(f)
bin[1]=next(f)
bin[2]=next(f)
bin[3]=next(f)
bin[4]=next(f)
bin[5]=next(f)
bin[6]=next(f)
bin[7]=next(f)
Based on andybuckley's answer, you can get it done like this:
d = {}
f = open("tennis.txt")
for i, l in enumerate(f):
# cut the '0b' chars, so you will get your dict keys just like you want
bin_num = bin(i)[2:]
# if the key is shorter than 3 chars, add 0 to the beginning
while len(bin_num) < 3:
bin_num = '0' + bin_num
d[bin_num] = l[:-1]
f.close()
for i in sorted(d.items()):
print i
EDIT : Thanks to #pepr - remember to close the opened file.
Output:
('000', 'Anna')
('001', 'David')
('010', 'Dennis')
('011', 'Morgan')
('100', 'Lana')
('101', 'Peter')
('110', 'Joanna')
('111', 'Karen')
It's a bit hard to know what you want: I've interpreted the question as wanting to read names from a text file, and to insert each into a dict with an increasing binary key. Here's an interactive Python3 session which does that and shows the populated dictionary:
>>> d = {}
>>> for i, l in enumerate(open("tennis.txt")):
... d[bin(i)] = l[:-1]
>>> d
{'0b10': 'Dennis', '0b11': 'Morgan', '0b110': 'Joanna', '0b0': 'Anna', '0b1': 'David', '0b101': 'Peter', '0b100': 'Lana', '0b111': 'Karen'}
Note that I've used "d" rather than "dict" as the name for the dictionary variable, since I don't want the variable name to hide the class name: it's always a good idea to avoid using the same names for variables and classes, although Python will not object.
Use a dict comprehension, zfill, and enumerate:
with open('/tmp/names.txt') as f:
print({bin(k)[2:].zfill(3): v.strip() for k,v in enumerate(f)})
Prints:
{'000': 'Anna', '001': 'David', '011': 'Morgan', '010': 'Dennis', '101': 'Peter', '100': 'Lana', '110': 'Joanna', '111': 'Karen'}
If you don't know how many lines there are in the file in order to use the right number for zfill, you can just count them first:
with open(fn) as f:
i=max(ln for ln,line in enumerate(f) if line.strip())
print(i, bin(i)[2:])
fill=len(bin(i)[2:])
f.seek(0)
print({bin(k)[2:].zfill(fill): v.strip() for k,v in enumerate(f) if v.strip()})