How to use Dictionary Comprehension to keep a running sum - python

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)) }

Related

Convert python dictionary to uppercase

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.

Sort python list into dictionary of lists, based on property in list

I'm trying to sort a list of objects in python into a dictionary of lists via a property of the objects in the original list
I've done it below, but this feels like something I should be able to do using a dictionary comprehension?
for position in totals["positions"]:
if not hasattr(totals["positions_dict"], position.get_asset_type_display()):
totals["positions_dict"][position.get_asset_type_display()] = []
totals["positions_dict"][position.get_asset_type_display()].append(position)
Some self improvements
totals["positions_dict"] = {}
for position in totals["positions"]:
key = position.get_asset_type_display()
if key not in totals["positions_dict"]:
totals["positions_dict"][key] = []
totals["positions_dict"][key].append(position)
You could use itertools.groupby and operator.methodcaller in a dict comprehension:
from operator import methodcaller
from itertools import groupby
key = methodcaller('get_asset_type_display')
totals["positions_dict"] = {k: list(g) for k, g in groupby(sorted(totals["positions"], key=key), key=key)}
Using a defaultdict as suggested by #Jean-FrançoisFabre allows you to do it with a single call to get_asset_type_display() in one loop:
from collections import defaultdict
totals["positions_dict"] = defaultdict(list)
for position in totals["positions"]:
totals["positions_dict"][position.get_asset_type_display()].append(position)
Haven't tested this, because I don't have your data.
And I think it's rather ugly, but it just may work:
totals ['positions_dict'] = {
key: [
position
for position in totals ['positions']
if position.get_asset_type_display () == key
]
for key in {
position.get_asset_type_display ()
for position in totals ['positions']
}
}
But I would prefer something very simple, and avoid needless lookups / calls:
positions = totals ['positions']
positions_dict = {}
for position in positions:
key = position.get_asset_type_display ()
if key in positions_dict:
positions_dict [key] .append (position)
else:
positions_dict [key] = [position]
totals ['positions_dict'] = positions_dict
positions = totals ['positions']

Load options dictionary using generator expression

I have option file in this format:
key value\t\n
N:B:. Some values show tab after it.
I use Code like :
src = open("conf.cfg").readlines()
item = item.split(" ")[0:2]
key = item[0]
value = item[1]
dict_[key] = value
Can I use generator expression to get the same result ??
You could use a dictionary comprehension, for example:
with open("conf.cfg") as f:
dict_ = {key: value
for key, value in (line.strip().split(" ")[:2]
for line in f)}
Maybe this way:
with open('config.txt') as f:
dict_ = {k: v for k, v in (line.split() for line in f.readlines())}
Yes, you can use a generator expression, it would look like this:
with open("conf.cfg") as f:
dict_ = dict(line.split() for line in f)
I am assuming you don't have spaces in the keys or values. If you have spaces in them (and "they are quoted" strings) then it will be easier for you to read your file with the csv module.
Using generator function:
def myGenerator():
with open("conf.cfg") as f:
for line in f.readlines():
yield(line.split())
result = {k:v for k,v in myGenerator()}
print result

More concise way to append a value to a dict array-element?

When I want to append a newvalue into Dict under Key, I find myself have to write:
# Dict={}
# Key = ....
# newvalue = ....
if not Key in Dict:
Dict[Key] = [ newvalue ]
else:
Dict[Key].append(newvalue)
It costs four lines of code. Is there a more concise way with python standard library? e.g
Dict.appendkeyvalue(Key, newvalue)
You can use a defaultdict:
from collections import defaultdict
d = defaultdict(list)
d['something'].append(3)
print d['something']
# > [3]
With standard dictionaries, you can use setdefault():
d = {}
d.setdefault("something", []).append(3)
setdefault() here returns d["something"] if it exists, otherwise it creates a new dictionary entry with [] as its value and returns that.

Building count dictionary from statistics file

I have a statistics file like this:
dict-count.txt
apple 15
orange 12
mango 10
apple 1
banana 14
mango 4
I need to count the number of each element and create a dictionary like this: {'orange': 12, 'mango': 14, 'apple': 16, 'banana': 14}. I do the following to achieve this:
from __future__ import with_statement
with open('dict-count.txt') as f:
lines = f.readlines()
output = {}
for line in lines:
key, val = line.split('\t')
output[key] = output.get(key, 0) + int(val)
print output
I am particularly concerned about this part:
key, val = line.split('\t')
output[key] = output.get(key, 0) + int(val)
Is there a better way to do this? Or this is the only way?
Thanks.
For a small file, you can use .readlines(), but that will slurp the entire contents of the file into memory in one go. You can write this using the file object f as an iterator; when you iterate it, you get one line of input at a time.
So, the easiest way to write this is to use a defaultdict as #Amber already showed, but my version doesn't build a list of input lines; it just builds the dictionary as it goes.
I used terse variable names, like d for the dict instead of output.
from __future__ import with_statement
from collections import defaultdict
from operator import itemgetter
d = defaultdict(int)
with open('dict-count.txt') as f:
for line in f:
k, v = line.split()
d[k] += int(v)
lst = d.items()
# sort twice: once for alphabetical order, then for frequency (descending).
# Because the Python sort is "stable", we will end up with descending
# frequency, but alphabetical order for any frequency values that are equal.
lst.sort(key=itemgetter(0))
lst.sort(key=itemgetter(1), reverse=True)
for key, value in lst:
print("%10s| %d" % (key, value))
Use a defaultdict:
from __future__ import with_statement
from collections import defaultdict
output = defaultdict(int)
with open('dict-count.txt') as f:
for line in f:
key, val = line.split('\t')
output[key] += int(val)
print output

Categories

Resources