Guest User

Untitled

a guest
May 26th, 2018
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.34 KB | None | 0 0
  1. import typing
  2.  
  3. from chainable_iterator import ChainableIterator
  4.  
  5. Key, Value = typing.Any, typing.Any
  6. KeyPath = typing.List[Key]
  7. Predicate = typing.Callable[[KeyPath, Key, Value], bool]
  8. _Node = typing.NamedTuple('Node', (('key_path', KeyPath), ('data', typing.Dict)))
  9.  
  10.  
  11. def _match_all(_p: KeyPath, _k: Key, _v: Value) \
  12. -> bool:
  13. return True
  14.  
  15.  
  16. def _decompose_dict(the_dict: typing.Dict, predicate: Predicate = _match_all) \
  17. -> typing.Generator[typing.Tuple[KeyPath, Value], None, None]:
  18. root = ChainableIterator((_Node([], the_dict),))
  19. for node in root:
  20. key_path = node.key_path
  21. for k, v in node.data.items():
  22. key_path.append(k)
  23. if isinstance(v, dict):
  24. root.chain((_Node(key_path, v),))
  25. if predicate(key_path, k, v):
  26. yield key_path, v
  27. key_path = key_path[:-1]
  28.  
  29.  
  30. def _recompose_dict(items: typing.Iterator[typing.Tuple[KeyPath, Value]]) \
  31. -> typing.Dict:
  32. root = {}
  33. for path, value in items:
  34. base, last = root, len(path) - 1
  35. for i, key in enumerate(path):
  36. base = base.setdefault(key, {} if i < last else value)
  37. return root
  38.  
  39.  
  40. def filter_dict(the_dict: typing.Dict, predicate: Predicate = _match_all) \
  41. -> typing.Dict:
  42. return _recompose_dict(_decompose_dict(the_dict, predicate))
  43.  
  44.  
  45. if __name__ == '__main__':
  46. import json
  47.  
  48. data = {
  49. '*': {
  50. 'a': {
  51. 'x': {
  52. 1: None,
  53. },
  54. 'k': {'lorem': 'spam'},
  55. '-': [
  56. {
  57. 'h': 1,
  58. },
  59. {
  60. 'o': {
  61. '/1': 1,
  62. '/3': 3
  63. },
  64. },
  65. {
  66. 'h': 3,
  67. }
  68. ]
  69. },
  70. 'b': {
  71. 'y': {
  72. 1: None,
  73. },
  74. 'k': {'lorem': 'eggs'},
  75. '-': [
  76. {
  77. 'h': 4,
  78. },
  79. {
  80. '.': {
  81. '/4': 4,
  82. '/6': 6
  83. },
  84. },
  85. {
  86. 'h': 6,
  87. }
  88. ]
  89. },
  90. 'c': {
  91. 'z': {
  92. 1: None,
  93. },
  94. 'k': {'lorem': 'ipsum'},
  95. '-': [
  96. {
  97. 'h': 7,
  98. },
  99. {
  100. 'o': {
  101. '/7': 7,
  102. '/9': 9
  103. },
  104. },
  105. {
  106. 'h': 9,
  107. }
  108. ]
  109. }
  110. }
  111. }
  112.  
  113. print(json.dumps(filter_dict(data, lambda p, k, v: v is None), indent=2))
  114.  
  115. print()
  116.  
  117. print(json.dumps(filter_dict(data, lambda p, k, v: k == 'lorem' and v == 'ipsum'), indent=2))
  118.  
  119. print()
  120.  
  121. print(json.dumps(
  122. filter_dict(data,
  123. lambda p, k, v: isinstance(v, list) and any(map(
  124. lambda d: filter_dict(d, lambda p1, k1, v1: k1 == '.'), v))),
  125. indent=2))
Add Comment
Please, Sign In to add comment