在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)
我想知道怎么用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
/sum
和map
也可以用len(filter(...))
来替代(假设是 Python 2;在 Python 3 中,filter
返回的是一个迭代器,所以你得用len(list(filter(...)))
,这很浪费)。 - 它会对每种颜色遍历完整个
colors
列表一次,而不是只遍历一次。这使得在你不知道所有可能结果的情况下无法使用,并且在所有情况下效率都低。
唯一可能有人会说的“优点”是,它会包含那些没有出现的颜色的 0 计数。当然,用其他解决方案也很容易做到这一点。