Python: List of tuples: 比较所有的元组并检索元组的元素不等于任何其他元组的元组

Python: List of tuples: compare all tuples and retrive tuples where the elements of tuples are not equal to any other tuple

我有一个这样的元组列表:

z = [(408, 2, 5), (408, 2, 2), (181, 2, 2), (181, 2, 5), (907, 2, 6), (907, 2, 1), (276, 2, 5), (276, 2, 2), (100, 2, 1), (100, 2, 6), (408, 3, 5), (408, 3, 2), (181, 3, 2), (181, 3, 5), (907, 3, 6), (907, 3, 1), (276, 3, 5), (276, 3, 2), (100, 3, 6), (100, 3, 1), (907, 10, 6), (907, 10, 1), (100, 10, 1), (100, 10, 6), (907, 11, 6), (907, 11, 1), (100, 11, 6), (100, 11, 1)]

我要做的是将所有元组相互比较,return 元组中的每个元素对于所有其他元组都是唯一的。

在上面的列表中,任何元组的第一个元素的值都可以是 408, 181, 907, 276 or 100 第二个元素的值为 2, 3, 10 or 11 第三个元素值 1, 2, 5 or 6.

查询列表的输出将 return 四个元组,因为元组的元素二(实际上是元素 3)最多有四种可能性。示例输出:

[(408, 2, 5), (181, 3, 2), (907, 10, 6), (100, 11, 1)]

我尝试过使用 while 循环并分别遍历列表和元组的每个元素以删除列表的相应元素或创建一个单独的列表,但这种方法没有考虑所有可能性并且感觉不对:

i = 0
j = 1
try:
    while i < len(z):
        if z[i][0] == z[j][0] or z[i][1] == z[j][1] or z[i][2] == z[j][2]:
            del z[j]
        else:
            j += 1
            i += 1
except:
    pass

我也研究过集合,但据我所知,它只会删除重复的元组。

谢谢。

您可以使用双循环比较所有元组,并使用列表理解来实现可伸缩性:

i = 0
while i < len(z):
    j = i+1
    while j < len(z):
        if any([z[i][n]==z[j][n] for n in range(len(z[0]))]):
            del z[j] # Shift all values, so no need to update j
        else:
            j += 1
    i += 1

如果您想要具有唯一值的元组,而不是对应于实际输入元组之一的元组(因为您声明“... return 每个元组元组中的元素对于所有其他元组都是唯一的。")。

>>> list(zip(*(set(zz) for zz in zip(*z))))
[(408, 2, 1), (907, 3, 2), (276, 10, 5), (181, 11, 6)]

虽然很有趣,但出于显而易见的原因,我很难推荐它。


对发生的事情的解释:

zip(*z)

这个 "inverts" 元组列表,所以从 28 x 3 开始,这是 3 * 28。

(set(zz) for zz in zip(*z))

过滤每个 len-28 元组中的唯一值。这导致:

[{408, 907, 276, 181, 100}, {2, 3, 10, 11}, {1, 2, 5, 6}]

现在我们需要从中创建元组。我们可以再次使用 zip

zip(*(set(zz) for zz in zip(*z)))

幸运的是,zip 在第一个元素(即 4 长元组)用完时停止;它不需要所有元组的长度都是 5。