python set union操作与命名元组的表现不佳

时间:2017-08-30 13:58:24

标签: python set namedtuple python-collections

我想在python中创建一组namedtuple,能够使用union操作动态添加元素。

以下代码段创建了set namedtuple,表现良好。

from collections import namedtuple

B = namedtuple('B', 'name x')

b1 = B('b1',90)
b2 = B('b2',92)
s = set([b1,b2])
print(s)

打印

{B(name='b1', x=90), B(name='b2', x=92)}

现在,如果我创建了另一个namedtuple并使用set操作将其添加到我的union,则表明其行为不符合预期。

b3 = B('b3',93)
s = s.union(b3)
print(s)

代码段打印以下输出。

{93, B(name='b1', x=90), B(name='b2', x=92), 'b3'}

预期输出应为:

{B(name='b1', x=90), B(name='b2', x=92), B(name='b3', x=93)}

我误解了API吗? python2和3都显示相同的行为。

4 个答案:

答案 0 :(得分:4)

namedtuple实例是一个可迭代的项目。 set.union只是将当前集合与namedtuple中的项目合并。

但是,您想要的是将namedtuple放在另一个容器/ iterable中,因此合并是使用新的父迭代中包含的项(namedtuple)完成的:

s.union((b3,))

如果您真正想到运算符等价物,那就更明显了:

s = s | set(b3) # set(b3) -> {93, 'b3'}

与我们实际想要的相比:

s = s | {b3}

使用外部iterable执行 union

答案 1 :(得分:2)

union需要一个集合(或列表或其他可迭代的),但是您传递一个命名元组,它本身是一个可迭代的,但它提供了值,因此您将该值与值合并。试试这个:

s = s.union({b3})

答案 2 :(得分:1)

由于b3是可迭代的,union对其元素而不是元组本身起作用。将其替换为:

s = s.union([b3])

答案 3 :(得分:0)

set.union上的文档实际上解释了这一点:

  

@foreach($course->users->excercises as $excercise) {{ $excercise->pivot->grade }} @endforeach

     

使用集合中的元素和所有其他元素返回一个新集合。

因此,它将创建一个包含union(*others)

中所有元素的新集
others

在您的情况下(因为您将其分配回>>> set(b3) # these are the unique elements in your `b3` {93, 'b3'} >>> s.union(b3) # the union of the unique elements in "s" and "b3" {B(name='b1', x=90), 93, 'b3', B(name='b2', x=92)} ),您只需添加项目,从而避免完全创建新集:

s