自动列表生成;python
我为这个模糊的标题提前表示歉意,但我很难准确地概念化这个问题 我有一个脚本,可以检查某个自动列表生成;python,python,list,list-comprehension,Python,List,List Comprehension,我为这个模糊的标题提前表示歉意,但我很难准确地概念化这个问题 我有一个脚本,可以检查某个名称是否在文本中。如果名称在文本中,脚本会将一个1附加到专门用于该名称的列表中,如果该名称不在文本中,则会附加一个0 看起来是这样的: import re import csv from itertools import izip names = ['peter', 'john', 'thomas', 'george'] texts = ['peter is awesome', 'john is lazy'
名称
是否在文本中。如果名称在文本中,脚本会将一个1
附加到专门用于该名称的列表中,如果该名称不在文本中,则会附加一个0
看起来是这样的:
import re
import csv
from itertools import izip
names = ['peter', 'john', 'thomas', 'george']
texts = ['peter is awesome', 'john is lazy', 'thomas is thomas','george is curious']
peter_matched = []
john_matched = []
thomas_matched = []
george_matched = []
for text in texts:
for name in names:
if name == 'peter':
if re.match(name, text):
peter_matched.append(1)
else:
peter_matched.append(0)
if name == 'john':
if re.match(name, text):
john_matched.append(1)
else:
john_matched.append(0)
if name == 'thomas':
if re.match(name, text):
thomas_matched.append(1)
else:
thomas_matched.append(0)
if name == 'george':
if re.match(name, text):
george_matched.append(1)
else:
george_matched.append(0)
with open('output_names.csv', 'wb') as f:
w = csv.writer(f)
w.writerows(izip(texts, peter_matched, john_matched, thomas_matched, george_matched))
现在,正如您所看到的,这是一个丑陋的混搭if/else
语句。更麻烦的是,我必须为每个名称创建一个单独的专用列表,以保存匹配的信息,然后将其写入.csv
。在我的真实脚本中,我需要交叉引用数千条文本和数百个名称,因此为每个项目编写一个专门的名称匹配的列表并不是一项有趣的任务
所以我的问题是:是否可以告诉Python自动生成这些列表,方法是从名称
列表中获取一个项目的名称,并将其附加到一些预先存在的字符串中,如\u matched
换句话说,我希望自动创建列表peter_matched
,john_matched
,等等
提前谢谢 您应该创建列表的dict
,并根据name
字符串检索每个列表
names = ['peter', 'john', 'thomas', 'george']
texts = ['peter is awesome', 'john is lazy', 'thomas is thomas','george is curious']
matched = {n: [] for n in names}
for text in texts:
for name in names:
if re.match(name, text):
matched[name].append(1)
else:
matched[name].append(0)
print matched
# {'john': [0, 1, 0, 0], 'thomas': [0, 0, 1, 0], 'peter': [1, 0, 0, 0], 'george': [0, 0, 0, 1]}
你可以用字典来解释。您可以这样做:
from collections import defaultdict
counts = defaultdict(int)
for text in tests:
for name in names:
if name in text:
counts[name] += 1
或者,如果要查找精确的0和1,可以使用字符串类型初始化字典:
counts = defaultdict(str)
for text in tests:
for name in names:
counts[name] += '1' if name in text else '0'
不要为每个名称创建单独的列表,而是使用dict
类型,特别是:
此外,从示例中可以看出,您不需要使用正则表达式。改为在
中使用一个,因为它更快。使用dict comprehension的一行代码(从python 2.7开始):
按名称创建dict名称
按键构建字典(经典方式):
奖励:pytest测试
如果要通过pytest对其进行测试,请将以下代码放入test\u names.py
:
import pytest
@pytest.fixture
def names():
return ['peter', 'john', 'thomas', 'george']
@pytest.fixture
def texts():
return [
'peter is awesome',
'john is lazy',
'thomas is thomas',
'george is curious']
def check_names(names, texts):
res = {}
for name in names:
res[name] = [1 if name in text else 0 for text in texts]
return res
def check_names2(names, texts):
res = {name: [1 if name in text else 0
for text in texts
]
for name in names
}
return res
def test_it(names, texts):
expected_result = {"peter": [1, 0, 0, 0],
"john": [0, 1, 0, 0],
"thomas": [0, 0, 1, 0],
"george": [0, 0, 0, 1],
}
result = check_names2(names, texts)
assert result == expected_result
跑
$ py.test -sv test_names.py
第一部分很简单,将名称列表转换为空列表字典
names = {name:[] for name in names}
填写清单也很容易
for t in texts:
for n in names:
names[n].append(1 if n in t else 0)
(请注意,对于您给出的示例,regexp是多余的)
最难的部分,imho,是将你的结果以一种与你展示的最相似的方式写入文件。。。我之所以插入标题行,是因为names.values()
不会以给定的顺序返回列表,但您可以确信.values()
的顺序与.keys()
的顺序相同,因此,在我看来,使用names
的键编写标题行似乎是获得有用CSV的更简单方法
with open('output_names.csv', 'w') as f:
w = csv.writer(f)
w.writerow(['text']+list(names.keys()))
w.writerows(zip(texts, *names.values()))
结果是
$ cat output_names.csv
text,john,george,peter,thomas
peter is awesome,0,0,1,0
john is lazy,1,0,0,0
thomas is thomas,0,0,0,1
george is curious,0,1,0,0
$
第一个想法是:如果您的正则表达式搜索是沿着'peter'
的路线进行的,那么就没有必要使用正则表达式。只需在
操作符中使用。第二个想法:你在找计数器吗?我更喜欢这样的字典{“peter”:[1,0,0,1]}
我使用regex作为例子,因为我需要在我的真实脚本中使用regex。确实,这在这里是多余的。如果CSV的创建对您很重要,我下面的回答也解决了这个问题。@GBOFI yes!非常感谢。如果重新匹配(名称、文本):
而不是如果文本中的名称:
或如果文本.startswith(名称)
,那么.csv肯定非常重要?比正则表达式更快更清晰。
for t in texts:
for n in names:
names[n].append(1 if n in t else 0)
with open('output_names.csv', 'w') as f:
w = csv.writer(f)
w.writerow(['text']+list(names.keys()))
w.writerows(zip(texts, *names.values()))
$ cat output_names.csv
text,john,george,peter,thomas
peter is awesome,0,0,1,0
john is lazy,1,0,0,0
thomas is thomas,0,0,0,1
george is curious,0,1,0,0
$