1

我正在尝试获取列表中每个项目在 Python 中的字符串中的次数:

paragraph = "I eat bananas and a banana"

def tester(x): return len(re.findall(x,paragraph))

map(tester, ['banana', 'loganberry', 'passion fruit'])

返回 [2, 0, 0]

然而,我想做的是扩展它,以便我可以将段落值输入 map() 函数。现在, tester() 函数已经对段落进行了硬编码。有没有人有办法做到这一点(也许制作一个 n 长度的段落值列表)?这里还有其他想法吗?

请记住,每个数组值在将来的某个时间点都会有一个权重——因此需要将这些值保存在一个列表中,而不是将它们全部一起处理。

更新:段落通常为 20K,列表通常有 200 多个成员。我的想法是 map 并行运行 - 所以它会比任何串行方法更有效。

4

7 回答 7

8

关闭将是一个快速的解决方案:

paragraph = "I eat bananas and a banana"

def tester(s): 
    def f(x):
        return len(re.findall(x,s))
    return f

print map(tester(paragraph), ['banana', 'loganberry', 'passion fruit'])
于 2009-07-22T21:57:41.173 回答
3
targets = ['banana', 'loganberry', 'passion fruit']
paragraph = "I eat bananas and a banana"

print [paragraph.count(target) for target in targets]

不知道为什么要在这里使用 map() 。

于 2009-07-22T23:06:47.583 回答
2

我知道您没有要求列表理解,但无论如何:

paragraph = "I eat bananas and a banana"
words = ['banana', 'loganberry', 'passion fruit']
[len(re.findall(word, paragraph)) for word in words]

这也返回 [2, 0, 0]。

于 2009-07-22T22:34:55.683 回答
2

这基本上只是为了避免列表理解,但如果你喜欢函数式编程,那么你会喜欢functools.partial

>>> from functools import partial
>>> def counter(text, paragraph):
    return len(re.findall(text, paragraph))

>>> tester = partial(counter, paragraph="I eat bananas and a banana")
>>> map(tester, ['banana', 'loganberry', 'passion fruit'])
[2, 0, 0]
于 2009-07-22T23:19:36.607 回答
1

对于大小为 T 字节的大文本上的平均长度为 L 字节的 Q 查询词,您需要不是 O(QLT) 的东西。您需要一种 DFA 风格的方法,它可以在设置成本之后为您提供 O(T) ...... 如果您的查询集相当静态,则可以忽略设置成本。

例如http://en.wikipedia.org/wiki/Aho-Corasick_algorithm
,它指向 Python 的 C 扩展:
http://hkn.eecs.berkeley.edu/~dyoo/python/ahocorasick/

于 2009-07-23T15:58:19.440 回答
1

这是对球门柱移动的回应(“我可能需要正则表达式,因为在不久的将来我需要单词分隔符”):

此方法解析文本一次以获得所有“单词”的列表。在目标词的字典中查找每个词,如果是目标词,则对其进行计数。花费的时间是 O(P) + O(T),其中 P 是段落的大小,T 是目标词的数量。迄今为止,除了我的 Aho-Corasick 解决方案之外的所有其他解决方案(包括当前接受的解决方案)都是 O(PT)。

def counts_all(targets, paragraph, word_regex=r"\w+"):
    tally = dict((target, 0) for target in targets)
    for word in re.findall(word_regex, paragraph):
        if word in tally:
            tally[word] += 1
    return [tally[target] for target in targets]

def counts_iter(targets, paragraph, word_regex=r"\w+"):
    tally = dict((target, 0) for target in targets)
    for matchobj in re.finditer(word_regex, paragraph):
        word = matchobj.group()
        if word in tally:
            tally[word] += 1
    return [tally[target] for target in targets] 

finditer 版本是一个稻草人——它比 findall 版本慢得多。

这是目前接受的解决方案,以标准化形式表示并增加了单词分隔符:

def currently_accepted_solution_augmented(targets, paragraph):
    def tester(s): 
        def f(x):
            return len(re.findall(r"\b" + x + r"\b", s))
        return f
    return map(tester(paragraph), targets)

这在关闭时太过分了,可以减少为:

# acknowledgement:
# this is structurally the same as one of hughdbrown's benchmark functions
def currently_accepted_solution_augmented_without_extra_closure(targets, paragraph):
    def tester(x):
        return len(re.findall(r"\b" + x + r"\b", paragraph))
    return map(tester, targets)

当前接受的解决方案的所有变体都是 O(PT)。与当前接受的解决方案不同,带有单词分隔符的正则表达式搜索不等同于简单的paragraph.find(target). 因为在这种情况下重新引擎不使用“快速搜索”,所以添加单词分隔符会将其从缓慢变为非常缓慢。

于 2009-07-24T03:21:15.057 回答
0

这是我的版本。

paragraph = "I eat bananas and a banana"

def tester(paragraph, x): return len(re.findall(x,paragraph))

print lambda paragraph: map(
    lambda x: tester(paragraph, x) , ['banana', 'loganberry', 'passion fruit']
        )(paragraph)
于 2009-07-22T23:16:55.847 回答