【问题标题】:Good and pythonic way to filter list of dictionaries with regular expressions用正则表达式过滤字典列表的好方法和pythonic方法
【发布时间】:2025-12-26 01:45:11
【问题描述】:

假设我有一个这样的列表/元组。

dic = ({name: 'Kan',number: '2ABC345', year: '2000'}, 
 {name: 'Jhon',number: '2TTC345', year: '2001'},
 {name: 'Louise',number: '2ABC366', year: '2001'},
 {name: 'Kevin',number: '2ABY000', year: '2002'})

如何在此列表中使用过滤器和正则表达式? 我正在考虑这样的事情,但我似乎无法更正代码。

 def func(dic, expression, keysection):
    r = re.compile(dic)
    x = list(filter(lambda x: r.findall(rexpression) in x[keysection], dic))
    print(x)

假设我想要 2000 年,我会做这样的事情,

func(dic, 2000, 'year')
>>> [{name: 'Kan',number: '2ABC345', year: 2000}]

或者名字的第一个字母是k,

func(dic, '^K', 'name')
>>> [ {name: 'Kan',number: '2ABC345', year: 2000}, {name: 'Kevin',number: '2ABY000', year: 2002}]

或者看数字是否以2开头,有7个数字,

func(dic, '2\d{7}', 'number')
>>> [ {name: 'Kan',number: '2ABC345', year: 2000}, {name: 'Jhon',number: '2TTC345', year: 2001},{name: 'Louise',number: '2ABC366', year: 2001}, {name: 'Kevin',number: '2ABY000', year: 2002} ]

问题是,我是正则表达式的新手,我不确定上面的代码是否正确,以及使用正则表达式过滤器的最佳和最 Python 的方式是什么。

【问题讨论】:

  • 您尝试实现的所有功能都已存在于filter() 中。你通过 callable 哪个检查条件,这是最“pythonic”的方式。
  • 是的,但我不知道如何将它与正则表达式一起使用
  • filter(lambda d: re.match(r'2\d{6}', d['number']), dic)
  • dic 中的所有键都必须是字符串。否则,您将调用变量 name,例如。
  • 不明白你是在谈论年份键,如果是的话,它也会在字符串中

标签: python python-3.x regex dictionary


【解决方案1】:

我不会尝试创建一个包含所有这些职责的函数。这将使测试变得异常困难。相反,我会为每种情况使用最简单的列表推导:

import re

dic = (
    {"name": "Kan",    "number": "2ABC345", "year": 2000},
    {"name": "Jhon",   "number": "2TTC345", "year": 2001},
    {"name": "Louise", "number": "2ABC366", "year": 2001},
    {"name": "Kevin",  "number": "2ABY000", "year": 2002},
)


# So let's say I want the year 2000
year_2000 = [d for d in dic if d["year"] == 2000]

# or the first letter in name be a k
name_k = [d for d in dic if d["name"].startswith("K")]

# or to see if the number starts with 2 and has 7 numbers
starts_2_digits_7 = [d for d in dic if re.match(r"^2\d{6}$", d["number"])]

【讨论】:

  • 我了解,但我使用的是 CSV 文件,该文件是 dic 列表的来源,其中包含 1000 多个键/跨度>
  • @jhonny large csv + filtering + efficiency == pandas
【解决方案2】:

您不需要为它创建函数。正则表达式必须是可读的。 Lambda 完成了这项工作。

print(list(filter(lambda x: x['year'] == 2000, dic)))

# Output:
[{'name': 'Kan', 'number': '2ABC345', 'year': 2000}]

print(list(filter(lambda x: x['name'][0] == 'K', dic)))

# Output:
[{'name': 'Kan', 'number': '2ABC345', 'year': 2000},
 {'name': 'Kevin', 'number': '2ABY000', 'year': 2002}]

print(list(filter(lambda x: x['number'][0] == '2' and len(x['number']) == 7, dic)))

# Output:
[{'name': 'Kan', 'number': '2ABC345', 'year': 2000},
 {'name': 'Jhon', 'number': '2TTC345', 'year': 2001},
 {'name': 'Louise', 'number': '2ABC366', 'year': 2001},
 {'name': 'Kevin', 'number': '2ABY000', 'year': 2002}]

但我真的建议为此使用 pandas。

【讨论】:

    【解决方案3】:

    让我们从正则表达式作用于字符串的说明开始。 因此,您最好纠正您的 dic 以便每个字典 包含字符串(最初 year 是一个数字)。

    你应该做的第一个更正是re.compile(dic) 是错的。 您可以编译一个模式,而不是字典。

    而且由于您只执行您的模式一次,因此没有必要 提前编译。只使用 pattern 会更简单 参数(一个字符串)。

    你的功能可以是:

    def func(dic, pat, key):
        return list(filter(lambda x: re.search(pat, x[key]), dic))
    

    当您只想打印找到的内容时,只需 函数返回结果,当您调用该函数时 结果将被打印出来。

    试试func(dic, '2000', 'year')func(dic, '^K', 'name')。 它应该打印你想要的。

    但尝试运行 func(dic, '2\d{7}', 'number') 将返回 [] (一个空列表),因为您的数据样本中没有 number 包含 2 后跟 7 位数字。

    但是你可以例如运行func(dic, '2A[A-Z]{2}', 'number'),即查找 数字的字典包含:

    • '2A',
    • 然后是 2 个字母。

    这次你会得到:

    [{'name': 'Kan', 'number': '2ABC345', 'year': '2000'},
     {'name': 'Louise', 'number': '2ABC366', 'year': '2001'},
     {'name': 'Kevin', 'number': '2ABY000', 'year': '2002'}]
    

    编辑

    如果你的字典中有一些元素other是字符串, 您可以将它们转换为函数中的字符串。将您的功能更改为:

    def func(dic, pat, key):
        return list(filter(lambda x: re.search(pat, str(x[key])), dic))
    

    它也适用于源字典中的非字符串元素。

    【讨论】: