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

-2 投票
3 回答
14269 浏览
提问于 2025-04-17 15:02
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)

我想知道怎么用filter和reduce这两个函数来计算每个数字出现的次数。

有没有人能给我一些建议呢?

补充说明一下,我想统计的是某种类型的随机数字生成的次数,而不是列表里已有的数字!

3 个回答

-2

我觉得这个方法是最简单的解决方案。它不使用过滤器之类的东西,但看起来是个相当聪明的办法。

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

你也可以创建一个字典,而不是元组的列表……这取决于你使用的Python解释器版本。

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。

3

首先,你的 apply 函数没有使用它的参数,这对于你要给 map 的东西来说可不是个好兆头。我猜你是想生成一个叫 colors 的随机颜色列表,然后对它进行计数;你也可以用生成器来替代这个。

像 filter、reduce 这些都是函数式编程的概念,通常在 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;在 Python 3 中,filter 返回的是一个迭代器,所以你得用 len(list(filter(...))),这很浪费)。
  • 它会对每种颜色遍历完整个 colors 列表一次,而不是只遍历一次。这使得在你不知道所有可能结果的情况下无法使用,并且在所有情况下效率都低。

唯一可能有人会说的“优点”是,它会包含那些没有出现的颜色的 0 计数。当然,用其他解决方案也很容易做到这一点。

撰写回答