Aggregating key value pair in python - python

I have a question related to python code.
I need to aggregate if the key = kv1, how can I do that?
input='num=123-456-7890&kv=1&kv2=12&kv3=0'
result={}
for pair in input.split('&'):
(key,value) = pair.split('=')
if key in 'kv1':
print value
result[key] += int(value)
print result['kv1']
Thanks a lot!!

I'm assuming you meant key == 'kv1' and also the kv within input was meant to be kv1 and that result is an empty dict that doesn't need result[key] += int(value) just result[key] = int(value)
input = 'num=123-456-7890&kv1=1&kv2=12&kv3=0'
keys = {k: v for k, v in [i.split('=') for i in input.split('&')]}
print keys # {'num': '123-456-7890', 'kv2': '12', 'kv1': '1', 'kv3': '0'}
result = {}
for key, value in keys.items():
if key == 'kv1':
# if you need to increase result['kv1']
_value = result[key] + int(value) if key in result else int(value)
result[key] = _value
# if you need to set result['kv1']
result[key] = int(value)
print result # {'kv1': 1}
Assuming you have multiple lines with data like:
num=123-456-7890&kv1=2&kv2=12&kv3=0
num=123-456-7891&kv1=1&kv2=12&kv3=0
num=123-456-7892&kv1=4&kv2=12&kv3=0
Reading line-by-line in a file:
def get_key(data, key):
keys = {k: v for k, v in [i.split('=') for i in data.split('&')]}
for k, v in keys.items():
if k == key: return int(v)
return None
results = []
for line in [line.strip() for line in open('filename', 'r')]:
value = get_key(line, 'kv1')
if value:
results.append({'kv1': value})
print results # could be [{'kv1': 2}, {'kv1': 1}, {'kv1': 4}]
Or just one string:
with open('filename', 'r') as f: data = f.read()
keys = {k: v for k, v in [i.split('=') for i in data.split('&')]}
result = {}
for key, value in keys.items():
if key == 'kv1':
result[key] = int(value)
Console i/o:
c:\nathan\python\bnutils>python
Python 2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def get_key(data, key):
... keys = {k: v for k, v in [i.split('=') for i in data.split('&')]}
... for k, v in keys.items():
... if k == key: return int(v)
... return None
...
>>> results = []
>>> for line in [line.strip() for line in open('test.txt', 'r')]:
... value = get_key(line, 'kv1')
... if value:
... results.append({'kv1': value})
...
>>> print results
[{'kv1': 2}, {'kv1': 1}, {'kv1': 4}]
>>>
test.txt:
num=123-456-7890&kv1=2&kv2=12&kv3=0
num=123-456-7891&kv1=1&kv2=12&kv3=0
num=123-456-7892&kv1=4&kv2=12&kv3=0

import urlparse
urlparse.parse_qs(input)
results in: {'num': ['123-456-7890'], 'kv2': ['12'], 'kv': ['1'], 'kv3': ['0']}
The keys are aggregated for you.

You could do it this way, so basically just add an extra if else block dealing with the empty case for key
input='num=123-456-7890&kv=1&kv2=12&kv3=0'
result={}
for pair in input.split('&'):
temp = pair.split('=')
key = temp[0]
value = [1]
if key in 'kv1':
if key in p:
print value //do you really want to output this?
result[key] += int(value)
else:
print value //do you really want to output this?
result[key] = int(value)
print result['kv1']

Related

How edit python dict in example?

I have a dict:
my_dict = {'some.key' : 'value'}
and i want to change it like this:
result = {'some' : {'key' : 'value'}}
how i can do this?
I need to this to create nested classes using dicts:
example:
my_dict = {'nested.key' : 'value'}
class Nested:
key : str
class MyDict:
nested : Nested
if you need this for real use, and not as a coding exercise, you can install extradict and use extradict.NestedData:
In [1]: from extradict import NestedData
In [2]: a = NestedData({'some.key' : 'value'})
In [3]: a["some"]
Out[3]: {'key': <str>}
In [4]: a["some"]["key"]
Out[4]: 'value'
In [5]: a.data
Out[5]: {'some': {'key': 'value'}}
(disclaimer: I am the package author)
Not quite sure if I understand your question, but would
result = {key.split('.')[0]: {key.split('.')[1]: value} for key, value in my_dict.items()}
do the trick?
I hope this function will help you
def foo(obj):
result = {}
for k, v in obj.items():
keys = k.split('.')
caret = result
for i in range(len(keys)):
curr_key = keys[i]
if i == len(keys) - 1:
caret[curr_key] = v
else:
caret.setdefault(curr_key, {})
caret = caret[curr_key]
return result
with recurtion it could look like this (having all keys unique is essential):
my_dict = {'key0' : 'value0',
'nested.key' : 'value',
'nested1.nested1.key1' : 'value1',
'nested2.nested2.nested2.key2' : 'value2'}
def func(k,v):
if not '.' in k: return {k:v}
k1,k = k.split('.',1)
return {k1:func(k,v)}
res = {}
for k,v in my_dict.items():
res.update(func(k,v))
>>> res
'''
{'key0': 'value0',
'nested': {'key': 'value'},
'nested1': {'nested1': {'key1': 'value1'}},
'nested2': {'nested2': {'nested2': {'key2': 'value2'}}}}

Removing duplicate key and appending the value of the deleted key in Python

Let's say I've got some results like the below from iterating thru JSON file.
{257585701: [156173119], 667512043: [228087519], 821360748: [5350676] and more }
{136607969: [13510118], 667512043: [13510118], 257585701: [13510118] and more }
{....................more data..........}
{....................more data..........}
like 100s
Now, if I wanna delete the duplicate value and append the value (from deleted duplicate value) to the original key, how can I do that? I'm hoping to get something like this:
{257585701: [156173119,13510118 ], 667512043: [228087519, 13510118], 821360748: [5350676], 136607969: [13510118]}
My codes are:
import json
filepath = '../data/' # I have subdirectories and tons of json file
with open(filepath) as stream:
data = json.load(stream)
results = {}
for item in data['info']['items']:
cid = item['id']
for trainer in item['trainer']:
tid = trainer['id']
if tid not in trainers:
trainers[tid] = []
trainers[tid].append(cid)
print(results)
# this print(results) prints the dictionary I mentioned above and they're like 100s of them.
This iterates through all the keys in dict2 and if it is already present it appends the value, otherwise it adds a new key:
dict1 = {257585701: [156173119], 667512043: [228087519], 821360748: [5350676]}
dict2 = {136607969: [13510118], 667512043: [13510118], 257585701: [13510118]}
dict3 = dict1
for k, v in dict2.items():
if k in dict3.keys():
dict3[k] += v
else:
dict3[k] = v
print(dict3)
Output:
{257585701: [156173119, 13510118], 667512043: [228087519, 13510118], 821360748: [5350676], 136607969: [13510118]}
You can start here
def merge_dicts(*dicts):
d = {}
for dict in dicts:
for key in dict:
try:
d[key].append(dict[key])
except KeyError:
d[key] = [dict[key]]
return d
pass all dicts in merge_dicts(d1,d2,d3..)
Write functions.
I can't test the code fully because I don't have access to your input. I also had to guess the type of trainers. The following code hopefully approaches a solution.
from collections import defaultdict
import json
def read_one_json(filepath: str, trainers: [dict]) -> dict:
with open(filepath) as stream:
data = json.load(stream)
results = {}
for item in data['info']['items']:
cid = item['id']
for trainer in item['trainer']:
tid = trainer['id']
if tid not in trainers:
trainers[tid] = []
trainers[tid].append(cid)
return results
def read_jsons(filepaths: [str], trainers: [dict]) -> list[dict]:
jsons = []
for filepath in filepaths:
jsons.append(read_one_json(filepath, trainers))
return jsons
def combine_dicts(dicts: [dict]) -> dict:
"""
dicts is list of dicts of (int, [int]) pairs.
combine_dicts returns a new dict where the values of duplicate keys are combined
>>> dicts = [{257585701: [156173119], 667512043: [228087519], 821360748: [5350676]}]
>>> dicts += [{136607969: [13510118], 667512043: [13510118], 257585701: [13510118]}]
>>> combine_dicts(dicts)
defaultdict(<class 'list'>, {257585701: [156173119, 13510118], 667512043: [228087519, 13510118], 821360748: [5350676], 136607969: [13510118]})
"""
combined_data = defaultdict(list)
for data in dicts:
for key, value in data.items():
combined_data[key] += value
return combined_data
def main() -> None:
filepaths = [...] # you supply these
trainers = [...] # you supply these
separate_data = read_jsons(filepaths, trainers)
combined_data = combine_dicts(separate_data)
print(combined_data)
if __name__ == '__main__':
main()
You can try to ingest the data string into a list of dictionary and process from there.
I'm using dic.get(key, '') instead of dic['key'] for the same purpose, but without the key error if the key does not exist. When the key does not exist, it outputs the empty string '' specified.
data = """{257585701: [156173119], 667512043: [228087519], 821360748: [5350676]}
{136607969: [13510118], 667512043: [13510118], 257585701: [13510118]}
{136607969: [135101], 667512043: [135101], 257585701: [135101]}"""
#dict_list = [eval(e) for e in data.split('\n')] #NOT safe, do NOT use this!
import ast
dict_list = [ast.literal_eval(e) for e in data.split('\n')] #use this
Output dict_list
[{257585701: [156173119], 667512043: [228087519], 821360748: [5350676]},
{136607969: [13510118], 667512043: [13510118], 257585701: [13510118]},
{136607969: [135101], 667512043: [135101], 257585701: [135101]}]
I'm assuming data is from print results, and they are separated by new line \n, so they can be processed into Python dict above.
keys = []
result = {}
for dic in dict_list:
keys.extend(dic.keys())
keys = set(keys)
for key in keys:
result[key] = []
for dic in dict_list:
result[key] += dic.get(key, '')
print(result)
Output:
{136607969: [13510118, 135101],
667512043: [228087519, 13510118, 135101],
821360748: [5350676],
257585701: [156173119, 13510118, 135101]}

need help for condition statement for keys in python

conn = pywbem.WBEMConnection(server_uri, (user, password),default_namespace='root/cimv2')
#server = pywbem.WBEMServer(conn)
#help(conn)
#print("Interop name:\n %s" % conn.interop_ns)
#print ("All namespaces:")
#for ns in conn.namespaces:
# print(" %s" %ns)
ClassesToCheck = [
# 'OMC_SMASHFirmwareIdentity',
# 'CIM_Chassis',
# 'CIM_Memory',
'CIM_Processor',
]
for className in ClassesToCheck:
instance_list = conn.EnumerateInstances(className)
print instance_list
for instance in instance_list:
if verbose:
print
print 'Instance of : %s' %className
print '============================================================'
# print 'instanceName = %s' %instance
for key,value in instance.items():
#if key in [ModelName,Stepping,EnabledProcessorCharacteristics,CPUStatus]:
instance.items has lot of keys and value, I want to print particular keys values only.
Need logic for this
You could print a smaller dictionary:
for k, v in my_dict.items():
if some_condition(k):
print(k, ':', v)
or
print({ k: v for k, v in my_dict.items()
if some_condition(k) })
If you have a fixed list of keys you want to print, iterate over them:
my_keys = [ 'ModelName', 'Stepping',
'EnabledProcessorCharacteristics', 'CPUStatus']
for k in my_keys:
print(k, ':', my_dict[k])
or
print({ k: my_dict[k] for k in my_keys })

Conditionally change values of inner dict in python

I have dicts in dict and need to change where the value of inner dicts is None to 'None' so it could show in csv file, not to be a blank cell.
Example:
{Object1 : {cellload : 1, cellthr : None, cellcap : 40}
Object2 : {cellload : None, cellthr : 2, cellcap : 40}
...
ObjectN : {cellload : None, cellthr : 5, cellcap : 50}}
So, I don't need None or NaN values, that can't be recognized in csv file, I need 'None' as a string.
I've tried this:
def replace(main_dif):
for k, v in main_dif.items():
for ki, ve in v.items():
if ve is None:
ve = "None"
elif type(ve) == type(main_dif):
replace(ve)
replace(main_dif)
And this:
outer = {}
for k, v in main_dif.items():
inner = {}
for ki, ve in v.items():
if ve is None:
ve == 'None'
else:
ve = ve
inner.update({ki:ve})
outer.update({k:inner})
And None is there just like always, like I did nothing.
One option is just to brute-force through all the values of all the objects and replace the Nones.
for obj in objects:
for k,v in obj.items():
if v is None:
obj[k] = 'None'
EDIT It's best to use the python csv module where possible.
In this case we can make a custom DictWriter to handle the None situations for us (it might need tweaking depending on the data).
import csv
class NoneSafeWriter(csv.DictWriter):
def _extract_val(self, rowdict, key):
v = rowdict.get(key)
return 'None' if v == None else v
def _dict_to_list(self, rowdict):
return [self._extract_val(rowdict, key) for key in self.fieldnames]
with open('output.csv', 'w') as csvfile:
fieldnames = ['cellload', 'cellthr', 'cellcap']
writer = NoneSafeWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(objects.values())

Dot notation to Json in python

I receive data from the Loggly service in dot notation, but to put data back in, it must be in JSON.
Hence, I need to convert:
{'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}
Into:
{'message': {'code': {'response': 80}, 'status': {'time': 50}}, 'time': 100}
I have put together a function to do so, but I wonder if there is a more direct and simpler way to accomplish the same result.
def dot_to_json(a):
# Create root for JSON tree structure
resp = {}
for k,v in a.items():
# eliminate json. (if metric comes from another type, it will keep its root)
k = re.sub(r'\bjson.\b','',k)
if '.' in k:
# Field has a dot
r = resp
s = ''
k2 = k.split('.')
l = len(k2)
count = 0
t = {}
for f in k2:
count += 1
if f not in resp.keys():
r[f]={}
r = r[f]
if count < l:
s += "['" + f + "']"
else:
s = "resp%s" % s
t = eval(s)
# Assign value to the last branch
t[f] = v
else:
r2 = resp
if k not in resp.keys():
r2[k] = {}
r2[k] = v
return resp
You can turn the path into dictionary access with:
def dot_to_json(a):
output = {}
for key, value in a.iteritems():
path = key.split('.')
if path[0] == 'json':
path = path[1:]
target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
target[path[-1]] = value
return output
This takes the key as a path, ignoring the first json part. With reduce() you can walk the elements of path (except for the last one) and fetch the nested dictionary with it.
Essentially you start at output and for each element in path fetch the value and use that value as the input for the next iteration. Here dict.setdefault() is used to default to a new empty dictionary each time a key doesn't yet exist. For a path ['foo', 'bar', 'baz'] this comes down to the call output.setdefault('foo', {}).setdefault('bar', {}).setdefault('baz', {}), only more compact and supporting arbitrary length paths.
The innermost dictionary is then used to set the value with the last element of the path as the key.
Demo:
>>> def dot_to_json(a):
... output = {}
... for key, value in a.iteritems():
... path = key.split('.')[1:] # ignore the json. prefix
... target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
... target[path[-1]] = value
... return output
...
>>> dot_to_json({'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}))
{'message': {'status': {'time': 50}, 'code': {'response': 80}}, 'time': 100}

Categories