Python3-如何通过字典列表中的值搜索关键字?

时间:2019-12-11 18:14:54

标签: python dictionary

我有一个字典列表,格式如下:

dict = [{
  "users": {
    "user_a": [{
      "email": [ "aaa1@email.com", "aaa2@email.com" ]
    }],
    "user_b": [{ 
      "email": [ "bbb1@email.com" ]
    }]
  },
  "class": "class_A"
},
{
  "users": {
    "user_d": [{
      "email": [ "ddd1@email.com" ]
    }],
    "user_c": [{ 
      "email": [ "aaa1@email.com", "ccc@email.com" ]
    }]
  },
  "class": "class_B"
}]

我想找到其值包含电子邮件地址“ aaa1@email.com”的键(用户名),因此结果为:

class_A, user_a
class_B, user_c

我正在尝试这种方式:

for key, value in enumerate(dict):
  if key =="users":
    if value in "aaa1":

但是我从这里迷路了。 如何通过值获取密钥?

非常感谢您的帮助。

6 个答案:

答案 0 :(得分:1)

当您执行enumerate(dict)时,没有得到dict的值,而是告诉python给您列表的值和您所拥有的索引。

因此,您将获得第一个循环:

for index, value in enumerate(my_dict):
    print("index is {}".format(index))
    print("value is {}".format(value))
>>>index is 0
>>>value is {"users": ... }

所以您需要开始在值的内部查找以获取密钥

value["users"]["user_d"]

正如一些评论所提到的,该结构确实很难使用。如果可以的话,您最好简化一下。如果可以,请删除不必要的图层。

答案 1 :(得分:1)

假设您对当前的数据表示感到困惑,则可以使用flatten_data from my answer here来避免嵌套问题,这可以将您的数据结构转换成这样的字典:

{(0, 'class'): 'class_A',
 (0, 'users', 'user_a', 0, 'email', 0): 'aaa1@email.com',
 (0, 'users', 'user_a', 0, 'email', 1): 'aaa2@email.com',
 (0, 'users', 'user_b', 0, 'email', 0): 'bbb1@email.com',
 (1, 'class'): 'class_B',
 (1, 'users', 'user_c', 0, 'email', 0): 'aaa1@email.com',
 (1, 'users', 'user_c', 0, 'email', 1): 'ccc@email.com',
 (1, 'users', 'user_d', 0, 'email', 0): 'ddd1@email.com'}

这有点容易处理,因为现在您正在处理一个键,该键是一系列索引,您只在乎其中一些,而元素是类或电子邮件。

以下解决方案仅遍及所有字段,仅由于所有其他内容均为电子邮件,因此跳过"class"

data = [{'users': {'user_a': [{'email': ['aaa1@email.com', 'aaa2@email.com']}], 'user_b': [{'email': ['bbb1@email.com']}]}, 'class': 'class_A'}, {'users': {'user_d': [{'email': ['ddd1@email.com']}], 'user_c': [{'email': ['aaa1@email.com', 'ccc@email.com']}]}, 'class': 'class_B'}]

# traverse and flatten_data are copied from https://stackoverflow.com/a/36582214/5827215
def traverse(obj, prev_path = "obj", path_repr = "{}[{!r}]".format):
    if isinstance(obj,dict):
        it = obj.items()
    elif isinstance(obj,list):
        it = enumerate(obj)
    else:
        yield prev_path,obj
        return
    for k,v in it:
        yield from traverse(v, path_repr(prev_path,k), path_repr)

def _tuple_concat(tup, idx):
    return (*tup, idx)   
def flatten_data(obj):
    """converts nested dict and list structure into a flat dictionary with tuple keys
    corresponding to the sequence of indices to reach particular element"""
    return dict(traverse(obj, (), _tuple_concat))


# !! THIS IS FOR YOU

def extract_groups(flattened_data, matching_email):
    for path, elem in flattened_data.items():
        # path will have format like (0, 'users', 'user_b', 0, 'email', 0)
        # elem is an email address

        # skip class mentions, we will retrieve these as needed
        if len(path) == 2 and path[1] == "class":
            continue
        # final element will match the given email?
        if elem == matching_email:
            # unpack useful elements of path
            [cls_idx, _, username, *_] = path
            cls = flattened_data[cls_idx, 'class']
            yield cls, username


new_data = flatten_data(data)
##import pprint
##pprint.pprint(new_data)
print(*extract_groups(new_data, "aaa1@email.com"), sep="\n")

这确实适用于您的示例输出:

('class_A', 'user_a')
('class_B', 'user_c')

但是任何其他字段都会引起问题,因为它会访问那些认为这是电子邮件的人。因此应将提取函数编写为依赖于数据中一致的结构,使用path[2]来引用用户ID可能不稳定,但可能存在另一种编写方法,等等。

答案 2 :(得分:1)

您可以使用列表理解:

data = [{'users': {'user_a': [{'email': ['aaa1@email.com', 'aaa2@email.com']}], 'user_b': [{'email': ['bbb1@email.com']}]}, 'class': 'class_A'}, {'users': {'user_d': [{'email': ['ddd1@email.com']}], 'user_c': [{'email': ['aaa1@email.com', 'ccc@email.com']}]}, 'class': 'class_B'}]
email = "aaa1@email.com"
result = [[i['class'], j] for i in data for j, k in i['users'].items() if any(email in x['email'] for x in k)]

输出:

[['class_A', 'user_a'], ['class_B', 'user_c']]

答案 3 :(得分:0)

def get_users_by_email(data, email):
    results = []
    for record in data:
        for user, details in record["users"].items():
            emails = details[0]["email"]
            if email in emails:
                results.append((record["class"], user))
    return results


print(get_users_by_email(d, "aaa1@email.com"))
# [('class_A', 'user_a'), ('class_B', 'user_c')]

避免隐藏内置名称:

dict = {...

答案 4 :(得分:0)

您可以尝试以下方法:

 for d in dict:
     for key in d['users'].keys():
         if 'aaa1@email.com' in d['users'][key][0]['email']:
             print(d['class'],key)

答案 5 :(得分:0)

尝试

for k, d in dict[0].items():
    if str(d).find('aaa1') != -1:
        print(k)

但是,另一种选择对您不起作用,但也许对其他人来说是最后的选择

list(dict.keys())[list(dict.values()).index('value')]

在屏幕上打印

print(list(dict.keys())[list(dict.values()).index('value')])