how to convert python dictionary into parent-child relation? - python

input_dictionary= {'A': [{'B1': [{'C1': ['D2']}, {'C2': ['D3']}]}, {'B2': [{'C1': ['D2']}, {'C2': ['D3']}]}]}
Output:
['A','A_B1','A_B2','A_B1_C1','A_B1,C2',.....so on]
So, the generic format is parent_child_subchild and so on.
Any advice/guideline would be appreciated.

>>> def stringify(d, prefix=[]):
... try:
... for k,l in d.items():
... return ['_'.join(prefix+[k])]+[f for e in l for f in stringify(e,prefix+[k])]
... except AttributeError:
... return ['_'.join(prefix+[d])]
...
>>> stringify(input_dictionary)
['A', 'A_B1', 'A_B1_C1', 'A_B1_C1_D2', 'A_B1_C2', 'A_B1_C2_D3', 'A_B2', 'A_B2_C1', 'A_B2_C1_D2', 'A_B2_C2', 'A_B2_C2_D3']

Related

List that resembles a dict to dict

I have a list that already quite resembles a dictionary:
l=["'S':'NP''VP'", "'NP':'DET''N'", "'VP':'V'", "'DET':'a'", "'DET':'an'", "'N':'elephant'", "'N':'elephants'", "'V':'talk'", "'V':'smile'"]
I want to create a dictionary keeping all information:
dict= {'S': [['NP','VP']],
'NP': [['DET', 'N']],
'VP': [['V']], 'DET': [['a'], ['an']],
'N': [['elephants'], ['elephant']],
'V': [['talk'], ['smile]]}
I tried using this:
d = {}
elems = filter(str.isalnum,l.replace('"',"").split("'"))
values = elems[1::2]
keys = elems[0::2]
d.update(zip(keys,values))
and this:
s = l.split(",")
dictionary = {}
for i in s:
dictionary[i.split(":")[0].strip('\'').replace("\"", "")] = i.split(":")[1].strip('"\'')
print(dictionary)
You can use collections.defaultdict with re:
import re, collections
l=["'S':'NP''VP'", "'NP':'DET''N'", "'VP':'V'", "'DET':'a'", "'DET':'an'", "'N':'elephant'", "'N':'elephants'", "'V':'talk'", "'V':'smile'"]
d = collections.defaultdict(list)
for i in l:
d[(k:=re.findall('\w+', i))[0]].append(k[1:])
print(dict(d))
Output:
{'S': [['NP', 'VP']], 'NP': [['DET', 'N']], 'VP': [['V']], 'DET': [['a'], ['an']], 'N': [['elephant'], ['elephants']], 'V': [['talk'], ['smile']]}

parse empty string using json

I was wondering if there was a way to use json.loads in order to automatically convert an empty string in something else, such as None.
For example, given:
data = json.loads('{"foo":"5", "bar":""}')
I would like to have:
data = {"foo":"5", "bar":None}
Instead of:
data = {"foo":"5", "bar":""}
You can use a dictionary comprehension:
data = json.loads('{"foo":"5", "bar":""}')
res = {k: v if v != '' else None for k, v in data.items()}
{'foo': '5', 'bar': None}
This will only deal with the first level of a nested dictionary. You can use a recursive function to deal with the more generalised nested dictionary case:
def updater(d, inval, outval):
for k, v in d.items():
if isinstance(v, dict):
updater(d[k], inval, outval)
else:
if v == '':
d[k] = None
return d
data = json.loads('{"foo":"5", "bar":"", "nested": {"test": "", "test2": "5"}}')
res = updater(data, '', None)
{'foo': '5', 'bar': None,
'nested': {'test': None, 'test2': '5'}}
You can also accomplish this with the json.loads object_hook parameter. For example:
import json
import six
def empty_string2none(obj):
for k, v in six.iteritems(obj):
if v == '':
obj[k] = None
return obj
print(json.loads('{"foo":"5", "bar":"", "hello": {"world": ""}}',
object_hook=empty_string2none))
This will print
{'foo': '5', 'bar': None, 'hello': {'world': None}}
This way, you don't need additional recursion.
I did some trial and error and it is impossible to parse None into a String using json.loads() you will have to use json.loads() with json.dumps() like I do in this example:
import json
data = json.loads('{"foo":"5", "bar":"%r"}' %(None))
data2 = json.loads(json.dumps({'foo': 5, 'bar': None}))
if data2['bar'] is None:
print('worked')
print(data['bar'])
else:
print('did not work')

Howto migrate vertical array to horizontal?

I am using Python 2; how can I migrate an array to multiple dimensions? example:
a = ['a', 'b', 'c', ...]
To:
foo['a']['b']['c']...
And check if exist, example have multiple arrays:
a = ['a', 'b', 'c']
b = ['a', 'x', 'y']
The result:
foo['a'] -> ['b'], ['x']
foo['a']['b'] -> ['c']
foo['a']['x'] -> ['y']
I need this for making a file dir tree navigation, for each path discovered need add the paths and files, the paths is get from db. Need separate a navigation by example:
http://foo.site/a ->
/b
/c
/d
http://foo.site/a/b ->
/file1.jpg
/file2.jpg
For each path make a split by / and need make multisimensional array or dictionary with each path and files availables.
It's not really clear what you are asking,
Nevertheless, you can define a simple tree structure like this:
import collections
def tree():
return collections.defaultdict(tree)
And use it as follow:
foo = tree()
foo['a']['b']['c'] = "x"
foo['a']['b']['d'] = "y"
You get:
defaultdict(<function tree at 0x7f9e4829f488>,
{'a': defaultdict(<function tree at 0x7f9e4829f488>,
{'b': defaultdict(<function tree at 0x7f9e4829f488>,
{'c': 'x',
'd': 'y'})})})
Which is similar to:
{'a': {'b': {'c': 'x', 'd': 'y'})})})
EDIT
But you also ask for “For each path make a split by / and need make multidimensional array or dictionary with each path and files available.”
I usually use os.walk to search files in directories:
import os
import os.path
start_dir = ".."
result = {}
for root, filenames, dirnames in os.walk(start_dir):
relpath = os.path.relpath(root, start_dir)
result[relpath] = filenames
This solution works for me using eval and Dictionaries of dictionaries merge :
def __init__(self):
self.obj = {}
def setPathToObject(self, path):
path_parts = path.replace('://', ':\\\\').split('/')
obj_parts = eval('{ \'' + ('\' : { \''.join(path_parts)) + '\' ' + ('}' * len(path_parts)))
obj_fixed = str(obj_parts).replace('set([\'', '[\'').replace('])}', ']}').replace(':\\\\', '://')
obj = eval(obj_fixed)
self.obj = self.recMerge(self.obj.copy(), obj.copy())
return obj
def recMerge(self, d1, d2):
for k, v in d1.items():
if k in d2:
if all(isinstance(e, MutableMapping) for e in (v, d2[k])):
d2[k] = self.recMerge(v, d2[k])
elif all(isinstance(item, list) for item in (value, dict2[key])):
d2[key] = v + d2[k]
d3 = d1.copy()
d3.update(d2)
return d3
Testing:
setPathToObject('http://www.google.com/abc/def/ghi/file1.jpg')
setPathToObject('http://www.google.com/abc/xyz/file2.jpg')
setPathToObject('http://www.google.com/abc/def/123/file3.jpg')
setPathToObject('http://www.google.com/abc/def/123/file4.jpg')
print self.obj
> { 'http://www.google.com': { 'abc': { 'def': { 'ghi': [ 'file1.jpg' ], '123': [ 'file3.jpg', 'file4.jpg' ] }, 'xyz': [ 'file2.jpg' ] } } }
Works on Python 2.

How i make json.loads turn str into int

I need '-40' to be -40 on the output, how i can do this?
In [2]: foo
Out[2]: '{\n\t"rssiIntentRange":"-40"\n}'
In [3]: import json
In [4]: json.loads(foo)
Out[4]: {u'rssiIntentRange': u'-40'}
Im searching for something clean and generic. Doing treatments after the json.loads is what im already doing and its very dirty because of all types of data and indexes. If json.loads is not the best option im open to other approaches as well that treats JSON
If you want to influence what happens when you call json.loads(), you need to write an object hook:
import json
def int_please_object_hook(obj):
"""If a value in obj is a string, try to convert it to an int"""
rv = {}
for k, v in obj.items():
if isinstance(v, basestring):
try:
rv[k] = int(v)
except ValueError:
rv[k] = v
else:
rv[k] = v
return rv
j = '{"key1": "value1", "key2": "10", "key3": "-10"}'
print(json.loads(j))
# {'key1': 'value1', 'key2': '10', 'key3': '-10'}
print(json.loads(j, object_hook=int_please_object_hook))
# {'key1': 'value1', 'key2': 10, 'key3': -10}
One way to do this would be to convert the -40 string to int after loading the json.
Example -
>>> foo = '{\n\t"rssiIntentRange":"-40"\n}'
>>> import json
>>> d = json.loads(foo)
>>> d['rssiIntentRange'] = int(d['rssiIntentRange'])
>>> d
{'rssiIntentRange': -40}
For changing all such values inside the loaded dictionary, you can do -
d = json.loads(foo)
for k,v in d.items():
try:
d[k] = int(v)
except (ValueError, TypeError):
pass
Example/Demo -
>>> foo = '{\n\t"rssiIntentRange":"-40",\n\t"blah":"abcd",\n\t"anothernumber":"-10"\n}'
>>> d = json.loads(foo)
>>> for k,v in d.items():
... try:
... d[k] = int(v)
... except (ValueError, TypeError):
... pass
...
>>> d
{'blah': 'abcd', 'anothernumber': -10, 'rssiIntentRange': -40}

Python, How to efficiently make a nested dictionary from a list of lists

I have a list of lists that looks like this
[['ip1',404],
['ip1',200],
['ip1',200],
['ip2',200],
['ip2',200],
['ip2',504]]
I need to make a dictionary that has counts of the status codes by ip address.
results = {'ip1':{404:1,200:2},'ip2':{200:2,504:1}}
The tools in collections make short work of this problem:
>>> from collections import defaultdict, Counter
>>> d = defaultdict(Counter)
>>> for ip, code in [['ip1',404], ['ip1',200], ['ip1',200],
['ip2',200], ['ip2',200], ['ip2',504]]:
d[ip][code] += 1
>>> dict(d)
{'ip2': Counter({200: 2, 504: 1}), 'ip1': Counter({200: 2, 404: 1})}
>>> from collections import defaultdict
>>> d = defaultdict(lambda: defaultdict(int))
>>> ips = [['ip1',404],['ip1',200],['ip1',200],['ip2',200],['ip2',200],['ip2',504]]
>>> for ip,num in ips:
d[ip][num] += 1
>>> d
defaultdict(<function <lambda> at 0x00000000035D6648>, {'ip2': defaultdict(<class 'int'>, {200: 2, 504: 1}), 'ip1': defaultdict(<class 'int'>, {200: 2, 404: 1})})
try this:
values = [['ip1',404],
['ip1',200],
['ip1',200],
['ip2',200],
['ip2',200],
['ip2',504]]
counts = {}
for value in values:
ip, status_code = value
if ip not in counts:
counts[ip] = {}
if status_code not in counts[ip]:
counts[ip][status_code] = 0
counts[ip][status_code] += 1
{'ip2': {200: 2, 504: 1}, 'ip1': {200: 2, 404: 1}}
it should work on virtually any python version.
>>> l
[['ip1', 404],
['ip1', 200],
['ip1', 200],
['ip2', 200],
['ip2', 200],
['ip2', 504]]
>>> {ip: {code: l.count([ip, code])
... for code in (p[1] for p in l if p[0]==ip)}
... for ip in (p[0] for p in l)}
{'ip1': {200: 2, 404: 1}, 'ip2': {200: 2, 504: 1}}
L = [[ip1,404], [ip1,200], [ip1,200], [ip2,200], [ip2,200], [ip2,504]]
D = {}
for entry in L:
ip = entry[0]
code = entry[1]
ip_entry = D.get(ip, {})
ip_entry[code] = ip_entry.get(code, 0) + 1
D[ip] = ip_entry

Categories

Resources