在Python中使用filter和reduce计算出现次数

时间:2013-02-07 00:48:32

标签: python filter reduce

c=["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach"]
import random
import collections
def apply(T):
    i = random.randint(0, 7)
    return c[i]
for x in range(1, 50):
    for ch in map(apply, c):
        print(ch)

我试图通过仅使用过滤器和减少函数来计算如何计算每个数字的出现次数。

有人能指出我正确的方向吗?

编辑:对于澄清,我想计算某个类型的随机数生成的次数,而不是列表中的那个!

3 个答案:

答案 0 :(得分:2)

首先,你的apply函数忽略了它的参数,这对于你给map的东西来说绝不是一个好兆头。我假设您正在尝试生成一个名为colors的随机颜色列表,然后计算它;你也可以用发电机代替它。

过滤,减少等是函数式编程概念,通常可以通过Python中的列表推导或生成器更好地处理。我就是这样做的:

c = ["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach"]

import random
colors = [c[random.randrange(len(c))] for _ in range(50)]

# now, to count

# (a) the way you'd actually do it in practice:
from collections import Counter
counts = Counter(colors)

# (b) the way you'd actually do it without the collections module
counts = {}
for x in colors:
    if x not in counts:
        counts[x] = 0
    counts[x] += 1

# (c) doing it with reduce...technically.
def add_to_counter(counter, el):
    counter[el] += 1  # can't actually do this in a lambda...
counts = reduce(add_to_counter, colors, Counter())

您也可以执行与(c)类似的操作,但不仅仅使用Counter类来维护元素及其计数列表,并在reduce函数中添加它们,但这只是一个效率较低且更繁琐的版本同样的事情。

既然你说使用filter和reduce,我假设这是一个家庭作业。这很愚蠢,因为这些对于这个问题来说绝对是错误的工具。但是这里有一种非常低效且难以理解的方法来使用filter和reduce(以及map)来解决这个问题,这可能就像你的教师正在寻找的那样:

from functools import partial
import operator
counts = {}
for x in c:
    counts[x] = reduce(operator.add,
                       map(lambda _: 1, filter(partial(operator.eq, x), colors)),
                       0)

这太可怕了,因为:

  • 需要付出很多努力来弄清楚发生了什么,而不是上面(a)和(b)的显而易见性。
  • 你应该始终在Python中使用sum而不是reduce(operator.add, ...)
  • 因此,counts[x] = sum(1 for el in colors if el == x)是相同(不好)的算法,但可读性要高出一百万倍,而且启动时间要短得多。
  • 即便如此,reduce / summap也可以被len(filter(...))的调用所取代(假设Python 2;三,filter返回一个迭代器,所以你必须做len(list(filter(...))),这很浪费。)
  • 每次为每种颜色传递完整的colors列表,而不只是一次。这使得在您不知道可能结果的完整列表的情况下使用它是不可能的,并且在所有情况下效率都低得多。

有人可以声称的唯一可能的“优势”是它包含任何未出现的颜色的0计数。对于任何其他解决方案来说,这当然是微不足道的。

答案 1 :(得分:0)

@Dougal

使用reduce和lambda:

可以很好地计算列表
    c = ["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach", "test"]
    print reduce(lambda x, y: x + 1, c, 0)

注意reduce()的最后一个参数是0。

答案 2 :(得分:-2)

我认为这将是最简单的解决方案。它不使用过滤器等,但它似乎是非常聪明的解决方案

counts = [(colors.count(x), x) for x in set(colors)]

你也可以创建一个dict,而不是元组列表...取决于你使用的python解释器版本。