StructureDescriber

Run Settings
LanguagePython
Language Version
Run Command
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()
Editor Settings
Theme
Key bindings
Full width
Lines