如何创建索引某些键位置的字典?
How do I create a dictionary that indexes the location of certain keys?
我有一个 class 继承了 dict
对象。
my_subclassed_dict = SubclassedDictionary({
"id": {"value1": 144
"value2": "steve",
"more" {"id": 114}
},
"attributes": "random"
})
在 SubclassedDictionary
的 初始化 中,我希望生成符合特定条件的路径。
假设,如果我要提出这个条件,'index all numbers above 100' 这可能会访问 my_subclassed_dict.get_paths()
,然后 return 类似于这样的某种结构:
[
['id', 'value1'],
['id', 'more', 'id',]
]
简而言之,如何在实例化时为匹配特定条件的键生成路径的 subclass dict
?
编辑
因为有人要求示例实现。然而,这个问题是它不处理嵌套字典。
class SubclassedDictionary(dict):
paths = []
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, int):
if value > 100:
self.paths.append(key)
super(SubclassedDictionary, self).update(*args, **kwargs)
dictionary = {
"value1": 333,
"v2": 99,
"v2": 129,
"v3": 30,
"nested": {
"nested_value" 1000
}
}
new_dict = SubclassedDictionary(dictionary)
print(new_dict.paths) # outputs: ['v2','value1']
如果它按预期工作。
print(new_dict.paths)
会输出
[
['v2'],
['value1'],
['nested', 'nested_value']
]
据我了解,如果键的关联值匹配特定条件,您需要一个能够返回字典中字典键的字典。
class SubclassedDictionary(dict):
def __init__(self, new_dict, condition=None, *args, **kwargs):
super(SubclassedDictionary, self).__init__(new_dict, *args, **kwargs)
self.paths = []
self.get_paths(condition)
def _get_paths_recursive(self, condition, iterable, parent_path=[]):
path = []
for key, value in iterable.iteritems():
# If we find an iterable, recursively obtain new paths.
if isinstance(value, (dict, list, set, tuple)):
# Make sure to remember where we have been (parent_path + [key])
recursed_path = self._get_paths_recursive(condition, value, parent_path + [key])
if recursed_path:
self.paths.append(parent_path + recursed_path)
elif condition(value) is True:
self.paths.append(parent_path + [key])
def get_paths(self, condition=None):
# Condition MUST be a function that returns a bool!
self.paths = []
if condition is not None:
return self._get_paths_recursive(condition, self)
def my_condition(value):
try:
return int(value) > 100
except ValueError:
return False
my_dict = SubclassedDictionary({"id": {"value1": 144,
"value2": "steve",
"more": {"id": 114}},
"attributes": "random"},
condition=my_condition)
print my_dict.paths # Returns [['id', 'value1'], ['id', 'more', 'id']]
此实施有一些好处。一是您可以随时更改您的条件。在您的问题中,听起来这可能是您感兴趣的功能。如果您想要不同的条件,您可以轻松编写一个新函数并将其传递给 class 的构造函数,或者简单地调用 get_paths()
你的新条件。
在开发递归算法时,您应该考虑 3 件事。
1) What is my stopping condition?
在这种情况下,您的文字条件实际上并不是您的停止条件。当不再有要迭代的元素时,递归停止。
2) Create a non-recursive function
这很重要有两个原因(我稍后会谈到第二个)。第一个原因是它是封装您不希望消费者使用的功能的安全方法。在这种情况下,_get_paths_recursive()
有额外的参数,如果消费者掌握了这些参数,可能会破坏您的路径属性。
3) Do as much error handling before recursion (Second reason behind two functions)
第二个函数的另一个好处是您可以执行非递归操作。通常情况下,当您编写递归算法时,您将不得不在开始递归之前做一些事情。在这种情况下,我确保 condition
参数有效(我可以添加更多检查以确保其函数 returns 是一个布尔值,并接受一个参数)。我还重置了路径属性,这样如果 get_paths()
被多次调用,您就不会得到大量的路径。
最小的变化是这样的:
class SubclassedDictionary(dict):
def __init__(self, *args, **kwargs):
self.paths = [] # note instance, not class, attribute
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, int):
if value > 100:
self.paths.append([key]) # note adding a list to the list
# recursively handle nested dictionaries
elif isinstance(value, dict):
for path in SubclassedDictionary(value).paths:
self.paths.append([key]+path)
super(SubclassedDictionary, self).update(*args, **kwargs)
它给出了您正在寻找的输出:
>>> SubclassedDictionary(dictionary).paths
[['v2'], ['value1'], ['nested', 'nested_value']]
然而,更简洁的方法可能是使 paths
成为一个方法,并创建嵌套的 SubclassedDictionary
实例而不是字典,这也允许您在调用时指定规则而不是硬编码它。例如:
class SubclassedDictionary(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, dict):
temp[key] = SubclassedDictionary(value)
super(SubclassedDictionary, self).update(*args, **kwargs)
def paths(self, rule):
matching_paths = []
for key, value in self.items():
if isinstance(value, SubclassedDictionary):
for path in value.paths(rule):
matching_paths.append([key]+path)
elif rule(value):
matching_paths.append([key])
return matching_paths
在使用中,获取所有大于100
的整数的路径:
>>> SubclassedDictionary(dictionary).paths(lambda val: isinstance(val, int) and val > 100)
[['v2'], ['value1'], ['nested', 'nested_value']]
一个缺点是每次调用时都会重新创建路径列表。
值得注意的是,您目前没有正确处理 kwargs
(所以我的代码也没有!);看看例如 我在其中提供了一个答案,展示了如何实现与基本 dict
相匹配的接口。您当前代码的另一个问题是它不处理随后从字典中删除的键;我的第一个片段也没有,但是第二个片段每次都会重建路径列表,这不是问题。
我有一个 class 继承了 dict
对象。
my_subclassed_dict = SubclassedDictionary({
"id": {"value1": 144
"value2": "steve",
"more" {"id": 114}
},
"attributes": "random"
})
在 SubclassedDictionary
的 初始化 中,我希望生成符合特定条件的路径。
假设,如果我要提出这个条件,'index all numbers above 100' 这可能会访问 my_subclassed_dict.get_paths()
,然后 return 类似于这样的某种结构:
[
['id', 'value1'],
['id', 'more', 'id',]
]
简而言之,如何在实例化时为匹配特定条件的键生成路径的 subclass dict
?
编辑
因为有人要求示例实现。然而,这个问题是它不处理嵌套字典。
class SubclassedDictionary(dict):
paths = []
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, int):
if value > 100:
self.paths.append(key)
super(SubclassedDictionary, self).update(*args, **kwargs)
dictionary = {
"value1": 333,
"v2": 99,
"v2": 129,
"v3": 30,
"nested": {
"nested_value" 1000
}
}
new_dict = SubclassedDictionary(dictionary)
print(new_dict.paths) # outputs: ['v2','value1']
如果它按预期工作。
print(new_dict.paths)
会输出
[
['v2'],
['value1'],
['nested', 'nested_value']
]
据我了解,如果键的关联值匹配特定条件,您需要一个能够返回字典中字典键的字典。
class SubclassedDictionary(dict):
def __init__(self, new_dict, condition=None, *args, **kwargs):
super(SubclassedDictionary, self).__init__(new_dict, *args, **kwargs)
self.paths = []
self.get_paths(condition)
def _get_paths_recursive(self, condition, iterable, parent_path=[]):
path = []
for key, value in iterable.iteritems():
# If we find an iterable, recursively obtain new paths.
if isinstance(value, (dict, list, set, tuple)):
# Make sure to remember where we have been (parent_path + [key])
recursed_path = self._get_paths_recursive(condition, value, parent_path + [key])
if recursed_path:
self.paths.append(parent_path + recursed_path)
elif condition(value) is True:
self.paths.append(parent_path + [key])
def get_paths(self, condition=None):
# Condition MUST be a function that returns a bool!
self.paths = []
if condition is not None:
return self._get_paths_recursive(condition, self)
def my_condition(value):
try:
return int(value) > 100
except ValueError:
return False
my_dict = SubclassedDictionary({"id": {"value1": 144,
"value2": "steve",
"more": {"id": 114}},
"attributes": "random"},
condition=my_condition)
print my_dict.paths # Returns [['id', 'value1'], ['id', 'more', 'id']]
此实施有一些好处。一是您可以随时更改您的条件。在您的问题中,听起来这可能是您感兴趣的功能。如果您想要不同的条件,您可以轻松编写一个新函数并将其传递给 class 的构造函数,或者简单地调用 get_paths()
你的新条件。
在开发递归算法时,您应该考虑 3 件事。
1) What is my stopping condition?
在这种情况下,您的文字条件实际上并不是您的停止条件。当不再有要迭代的元素时,递归停止。
2) Create a non-recursive function
这很重要有两个原因(我稍后会谈到第二个)。第一个原因是它是封装您不希望消费者使用的功能的安全方法。在这种情况下,_get_paths_recursive()
有额外的参数,如果消费者掌握了这些参数,可能会破坏您的路径属性。
3) Do as much error handling before recursion (Second reason behind two functions)
第二个函数的另一个好处是您可以执行非递归操作。通常情况下,当您编写递归算法时,您将不得不在开始递归之前做一些事情。在这种情况下,我确保 condition
参数有效(我可以添加更多检查以确保其函数 returns 是一个布尔值,并接受一个参数)。我还重置了路径属性,这样如果 get_paths()
被多次调用,您就不会得到大量的路径。
最小的变化是这样的:
class SubclassedDictionary(dict):
def __init__(self, *args, **kwargs):
self.paths = [] # note instance, not class, attribute
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, int):
if value > 100:
self.paths.append([key]) # note adding a list to the list
# recursively handle nested dictionaries
elif isinstance(value, dict):
for path in SubclassedDictionary(value).paths:
self.paths.append([key]+path)
super(SubclassedDictionary, self).update(*args, **kwargs)
它给出了您正在寻找的输出:
>>> SubclassedDictionary(dictionary).paths
[['v2'], ['value1'], ['nested', 'nested_value']]
然而,更简洁的方法可能是使 paths
成为一个方法,并创建嵌套的 SubclassedDictionary
实例而不是字典,这也允许您在调用时指定规则而不是硬编码它。例如:
class SubclassedDictionary(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs) # use the free update to set keys
def update(self, *args, **kwargs):
temp = args[0]
for key, value in temp.items():
if isinstance(value, dict):
temp[key] = SubclassedDictionary(value)
super(SubclassedDictionary, self).update(*args, **kwargs)
def paths(self, rule):
matching_paths = []
for key, value in self.items():
if isinstance(value, SubclassedDictionary):
for path in value.paths(rule):
matching_paths.append([key]+path)
elif rule(value):
matching_paths.append([key])
return matching_paths
在使用中,获取所有大于100
的整数的路径:
>>> SubclassedDictionary(dictionary).paths(lambda val: isinstance(val, int) and val > 100)
[['v2'], ['value1'], ['nested', 'nested_value']]
一个缺点是每次调用时都会重新创建路径列表。
值得注意的是,您目前没有正确处理 kwargs
(所以我的代码也没有!);看看例如dict
相匹配的接口。您当前代码的另一个问题是它不处理随后从字典中删除的键;我的第一个片段也没有,但是第二个片段每次都会重建路径列表,这不是问题。