列表理解做重复工作

时间:2015-02-04 19:49:28

标签: python list-comprehension

我有一个正在运行的python脚本,它读入一个电话号码文件。其中一些电话号码无效。

import re

def IsValidNumber(number, pattern):
    isMatch = re.search(pattern, number)
    if isMatch is not None:
        return number

numbers = [line.strip() for line in open('..\\phoneNumbers.txt', 'r')]

然后我使用另一个列表理解来过滤掉不好的数字:

phonePattern = '^\d{10}$'
validPhoneNumbers = [IsValidNumber(x, phonePattern) for x in phoneNumbers 
    if IsValidNumber(x, phonePattern) is not None]
for x in validPhoneNumbers:
    print x

由于格式化,第二个列表理解跨越了两行。

问题是虽然IsValidNumber只应该在匹配有效时返回数字,但在无效匹配时它也会返回'None'。所以我不得不修改第二个列表理解包括:

if IsValidNumber(x, phonePattern) is not None

虽然这有效,但问题是对于列表中的每次迭代,函数执行两次。这样做有更清洁的方法吗?

4 个答案:

答案 0 :(得分:4)

你的isValidFunction应该返回True / False(顾名思义)。这样你的列表理解就变成了:

valid = [num for num in phoneNumbers if isValidNumber(num, pattern)]

当你在这里时,将numbers修改为生成器表达式而不是列表推导(因为你对效率感兴趣):

numbers = (line.strip() for line in open("..\\phoneNumbers.txt"))

答案 1 :(得分:2)

试试这个:

validPhoneNumbers = [x for x in phoneNumbers if isValidNumber(x, phonepattern)]

由于isValidNumber返回的传入号码与传入的号码相同,因此您实际上并不需要该号码。你只需要知道一个数字就完全返回了(这个数字是有效的)。

您也可以将整个事情与:

结合起来
validPhoneNumbers = [x.strip() for x in open('..\\phonenumbers.txt', 'r') if isValidNumber(x.strip(), phonePattern)]

答案 2 :(得分:2)

我会更改您的有效性检查方法,只是返回数字是否匹配,但不返回数字本身。

def is_valid_number(number):
    return re.search(r'^\d{10}$', number)

然后你可以过滤掉第一个列表理解中的无效数字:

numbers = [line.strip() for line in open('..\\phoneNumbers.txt', 'r')
    if is_valid_number(line.strip())]

答案 3 :(得分:0)

此处有许多选项,包括filter(None, map(isValidNumber, lines))。效率最高的可能是让正则表达式完成所有工作:

import re
numpat = re.compile(r'^\s*(\d{10})\s*$', re.MULTILINE)
filecontents = open('phonenumbers.txt', 'r').read()
validPhoneNumbers = numpat.findall(filecontents)

这样就不需要Python循环了,你可以得到经过验证的数字。