是否有可能为元组重新定义相等的运算符?

时间:2016-06-27 14:05:30

标签: python

我有一些代码,其中边缘表示为元组

(vertex_1, vertex_2)

我有表示平面嵌入面的边列表,如下例所示。

我需要搜索列表中是否存在边缘,但如果使用(v1, v2)(v2, v1),我需要返回true:

f1 = [(6, 1), (1, 2), (2, 7), (7, 6)]
(6,1) in f1
(1,6) in f1

True
False

5 个答案:

答案 0 :(得分:3)

您无法覆盖现有类型的相等方法,因此您必须创建自己的类型,然后需要使用自定义类型替换所有现有元组。

如果你的主要问题只是(6,1) in f1用例,那么也许你应该考虑为此创建一个方法:

def contains(t, lst):
    return (t[0], t[1]) in lst or (t[1], t[0]) in lst

然后你可以像这样使用它:

>>> f1 = [(6, 1), (1, 2), (2, 7), (7, 6)]
>>> contains((6, 1), f1)
True
>>> contains((1, 6), f1)
True

这实际上有一个好处,就是您不需要用不同的类型替换元组。因此,您可以按原样使用所有数据源。

答案 1 :(得分:1)

你应该创建一个元组子类并改变它的相等方法(__eq__):

class UnorderedTuple(tuple):
    def __eq__(self, other):
        return len(self) == len(other) and set(self) == set(other)

将适用于您的情况(元组长度== 2,如果元组元素是可以清除的 - 这是不可变的并具有明确定义的比较)

要将元组列表转换为无序元组列表,请执行以下操作:

f1 =  [UnorderedTuple(f_) for f_ in f1]

要对列表进行适当的包含查询(in运算符)可能会很慢 - 所以你最好有一个集合而不是列表:

set_f1 =  { UnorderedTuple(f_) for f_ in f1 }
(6,1) in set_f1
(1,6) in set_f1

此实现不会非常高效,因为它会为每个比较创建一个新的set。因此,如果你的元组总是两个元素,那么将__eq__方法解压缩就更有效了:

    def __eq__(self, other):
        return super(UnordoredTuple, self).__eq__(other) or (self[0] == other[1] and self[1] == other[0])

答案 2 :(得分:1)

  

"是否可以为元组重新定义相等的运算符"

排序。您无法在基本tuple类型上执行此操作,但您可以在子类上执行此操作:

 class MyTuple(tuple):
     def __eq__(self, other):
         orig_eq = super(MyTuple, self).__eq__(other)
         if orig_eq and orig_eq is not NotImplemented:
             return True
         else:
             return super(MyTuple, self).__eq__(other[::-1])

通常,这可能不是最好的方法。根据问题的限制,您可以尝试一组freezeset:

f1_set = {frozenset(tup) for tup in f1}
frozenset((1, 6)) in f1_set

这里的优势在于,如果您对同一数据进行多个成员资格测试,您可能会获得更好的运行时间(列表上的每个成员资格测试都是O(N),您需要这样做对于您要检查的每个项目最多两个,而您只有一个O(N)步骤来构建f1_set,然后每个成员资格测试都是O(1)

答案 3 :(得分:0)

像其他人发布的那样,你可以使用类来重新定义元组的相等运算符,但是你必须使用那个类来调用它,所以如果你有

<div class="container-fluid">
    <div class="row content">
        <div class="col-sm-3 sidenav hidden-xs">
            <h2>DRFM Cockpit</h2>
            <ul class="nav nav-pills nav-stacked">
                <li><a ng-controller="functionalitiesHandler"  ng-click="setMDRFunction()" >MDR</a></li>
                <li><a ng-controller="functionalitiesHandler"  ng-click="setADRFunction()" >ADR</a></li>

            </ul>
            <br>
        </div>
        <br>

        <div class="col-sm-9">           
            <div ng-if="MDR">
                <h1>Test 1</h1>
                <p>Test 1</p>
                <hr>
            </div>
           <div ng-if="ADR">
                <h1>Test 2</h1>
                <p>Test 2</p>
                <hr>
            </div>
        </div>
    </div>
</div>

比你必须使用:

class new_tuple:
    ...

我认为使用函数来确定元组是否在列表中更容易:

tuple = (1,6)
tuple = new_tuple(tuple)

答案 4 :(得分:0)

此问题的一般解决方案是使用multisets,它们是元素可能出现多次的集合。 -bash: exportToAndroid.sh: command not found模块定义了collections类,它是Counter的子类,实现了多重集。 dict键是多集的元素,值是键出现的次数。

这避免了对多集中元素数量的限制,并且已经可用。主要的缺点是我所知道的没有“冻结”,可清洗的版本。

示例:

dict

您可以直接使用>>> from collections import Counter >>> Counter((3, 6, 2, 4, 2, 8)) == Counter((8, 4, 3, 6, 2, 2)) True >>> Counter((3, 6, 2, 4, 2, 8)) == Counter((8, 4, 3, 6, 4, 2)) False 类,这可能是最简单的,但如果您想保留基础Counter表示,则可以使用tuple类来实现更一般的其他人提出的Counter子类的版本:

tuple

示例:

class MultisetTuple(tuple):
    def __eq__(self, other):
        return Counter(self) == Counter(other)