import json
from collections import defaultdict
from typing import Any, Dict, List, Optional, Union
def remove_null_values(data: Union[Dict, List, str]) -> Optional[Union[Dict, List, str]]:
if isinstance(data, dict):
return {k: v for k, v in ((k, remove_null_values(v)) for k, v in data.items()) if v is not None}
elif isinstance(data, list):
return [v for v in (remove_null_values(v) for v in data) if v]
elif isinstance(data, str):
return data.strip() or None
return data
def find_n_grams(input_list: List[Any], n: int = 2):
return zip(*[input_list[i:] for i in range(n)])
class StructureDescriber:
"""
Usage:
s = StructureDescriber()
s.insert(<python obj: list or dict>)
s.describe()
"""
def __init__(self, scan_depth: int = 4, collect_data: Optional[List[str]] = None):
self.STRUCTURE = defaultdict(lambda: {'type': defaultdict(int)})
self.collect_data = set(collect_data) if collect_data else set()
self.scan_depth = scan_depth
@staticmethod
def get_type(data: Any) -> str:
type_of_data = type(data).__name__
if not data and type_of_data not in ('bool', 'int', 'float'):
type_of_data = f'empty_{type_of_data}'
return type_of_data
def insert(self, data: Any, level: int = 0, prefix: Optional[str] = None):
if level > self.scan_depth:
return
type_of_data = self.get_type(data)
if prefix:
self.STRUCTURE[prefix]['type'][type_of_data] += 1
if prefix in self.collect_data:
self.STRUCTURE[prefix].setdefault('data', {}).setdefault(data, 0)
self.STRUCTURE[prefix]['data'][data] += 1
if type_of_data == 'dict':
for k, v in data.items():
self.insert(data=v, level=level + 1, prefix=f'{prefix}.{k}' if prefix else k)
elif type_of_data == 'list':
for v in data:
self.insert(data=v, level=level, prefix=f'{prefix}.*' if prefix else '*')
def describe(self):
print("__root__:")
for key, structure_data in sorted(self.STRUCTURE.items()):
if not key.endswith('*'):
data_types = dict(structure_data['type'])
if 'list' in data_types:
for t in self.STRUCTURE[f'{key}.*']['type']:
data_types[f'list_of_{t}'] = data_types['list']
data_types.pop('list')
# indent = (key.count('.') - key.count('*')) * '│ '
# print(f"{indent}├── {key} {data_types}")
# if key in self.collect_data:
# for d, c in sorted(structure_data['data'].items(), key=lambda item: item[1], reverse=True):
# print(f"│ {indent}├── {d} {c}")
indent = (key.count('.') - key.count('*')) * ' '
print(f' {indent}{key}:', [f'{dt} {co}' for dt, co in data_types.items()])
if key in self.collect_data:
for d, c in sorted(structure_data['data'].items(), key=lambda item: item[1], reverse=True):
print(f' {indent}- {d} {c}')
if __name__ == '__main__':
data = input()
data = json.loads(data)
collect_data = input()
collect_data = collect_data.split(',')
s = StructureDescriber(collect_data=collect_data)
for d in data:
s.insert(d)
s.describe()