减少字典值的并集会产生意外结果

赛龙

我想对所有字典值(在这种情况下是集合)进行并集。如果输入列表中只有两个字典,我只会得到预期的结果。

输入列表中的两个词典会产生预期的结果:

>>> reduce((lambda x, y: x['a'] | y['a']), [{'a': {1, 2}}, {'a': {3, 4}}])
set([1, 2, 3, 4])

输入列表中的三个词典会产生TypeError。

预期结果: set([1, 2, 3, 4, 5, 6])

>>> reduce((lambda x, y: x['a'] | y['a']), [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    reduce((lambda x, y: x['a'] | y['a']), [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}])
  File "<input>", line 1, in <lambda>
    reduce((lambda x, y: x['a'] | y['a']), [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}])
TypeError: 'set' object has no attribute '__getitem__'

一本词典输入列表中产生的字典,而不是一组。

预期结果: set([1, 2])

>>> reduce((lambda x, y: x['a'] | y['a']), [{'a': {1, 2}}])
{'a': set([1, 2])}

空的输入列表也会产生不同的TypeError。

预期结果: set([])

>>> reduce((lambda x, y: x['a'] | y['a']), [])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    reduce((lambda x, y: x['a'] | y['a']), [])
TypeError: reduce() of empty sequence with no initial value

我需要帮助来了解我在做什么错以及为什么会产生这些结果。

宫城先生

TLDR:

reduce(function, iterable)调用以递归方式应用于先前结果的function元素这意味着的返回类型必须是有效的输入类型!iterable function

  • 在您的情况下,function期望dicts但产生一个set由于不可能调用x['y']a setTypeError因此引发a
  • iterable仅具有两个元素,function仅应用一次且仅于这些元件。function因此,永远不会遇到返回类型不是有效输入类型的问题。

您必须首先mapdictset然后 reducesets。

reduce(lambda x, y: x | y, map(lambda x: x['a'], [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}]))
#    merge via reduce ^     convert via map ^  

为什么reduce在某些情况下会失败

调用reduce(function, iterable)等效于以下代码:

def reduce(function, iterable, start=None):
    result = next(iterable) if start is None else start # 1.
    for element in iterable:
        result = function(result, element)              # 2.
    return result

这导致几种情况:

  1. iterable具有一个元件start未设置
    • resultiterable1.的第一个元素
      • function从不叫;它的返回和输入类型无关紧要
  2. iterable具有两个元件start未设置
    • result第一个元素iterable1.
    • function在第一个元素nextelement(2.上调用
      • function永远不会收到自己的结果;它的返回类型是没有意义的
  3. iterable两个以上的元素,并start没有设置
    • result第一个元素iterable1.
    • function在第一个元素next元素(2.上调用
    • function在上一个结果next元素(2.上调用
      • function得到自己的结果;其返回类型和输入类型必须匹配
  4. iterable空或不为空start已设置
    • 与上述相同,如果startiterable
  5. iterable空的,并start没有设置
    • result无法设置,并且TypeError引发(1.

您的情况是:

  • 两个词典是2.,并且按预期工作。
  • 三个字典是3.,它们在不兼容的输入和返回类型上很扼制。
  • 空的输入列表为5.,并且对缺少的输入失败-如预期的那样。

怎么做呢

地图/缩小

reduce实际上实际上是同时做两件事:它分别转换/提取每个元素,然后合并两个结果。那是一个经典的map / reduce任务:每个元素一个,所有元素一个。

您可以使用mapreduce内置函数将其直接分为两个单独的操作

sets = map(lambda x: x['a'], [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}])
result = reduce(lambda x, y: x | y, sets)

当然,您也可以直接嵌套这两个表达式。

理解/减少

map可以使用理解来表达部分。

sets = (x['a'] for x in [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}])
result = reduce(lambda x, y: x | y, sets)

理解/作业

在Python3.8中,您也可以使用赋值表达式代替reduce

result = set()
result = [(result := (result | x['a'])) for x in [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}]]

使用for循环

只是,你知道,写出来。

result = set()
for element in [{'a': {1, 2}}, {'a': {3, 4}}, {'a': {5, 6}}]:
    result |= element['a']

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章