自动列表生成;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
$