尝试使用python将矩阵放入集合中,但它仍然允许重复

时间:2013-01-08 21:00:03

标签: python matrix set

我有一段简单的代码没有按预期运行。

from numpy import *
from numpy.linalg import *
from sets import Set

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrices = Set([])
matrices.add(W)
matrices.add(E)
matrices

矩阵是相同的,但是当我打印集合的内容时它们都是单独出现的。但是,如果我像下面那样分配它,那么副本就不会出现。

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = W

知道发生了什么事吗?我需要一种避免在我编写的程序中重复矩阵的方法,这会生成一吨矩阵。

编辑:我想要以下输出

set([matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]])])

但请改为:

set([matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]]), matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]])])

4 个答案:

答案 0 :(得分:3)

这是因为集合使用 __ eq __ __ 哈希 __ 特殊方法来检测项目的相等性(见http://docs.python.org/2/library/sets.html)。但矩阵对象具有不同的哈希值,那些 __ eq __ 方法不会返回true / false,而是返回矩阵:

>>> W == E
matrix([[ True,  True,  True,  True],
        [ True,  True,  True,  True],
        [ True,  True,  True,  True],
        [ True,  True,  True,  True]], dtype=bool)
>>> W > E
matrix([[False, False, False, False],
        [False, False, False, False],
        [False, False, False, False],
        [False, False, False, False]], dtype=bool)

答案 1 :(得分:3)

你遇到的问题是python如何在内部检查对象之间的相似性。具体而言,如何比较被认为是“可混合”的对象。

python set构造函数决定两个对象是否相同的方式是基于调用名为__hash__的魔术方法(以及另一个名为__eq__的魔法)。如果在它们上调用__hash__的结果返回相同的值(并且它们上的caling __eq__返回True),则认为两个对象是相同的。如果在两个对象上调用__hash__给出不同的值,set假定它们不能被视为相同。

值得注意的是,只有 的集合包含被认为是“可散列”的对象,即实现__hash__方法的那些对象。

让我们看看它是如何工作的:

In [73]: a = "one"
In [74]: b = "one"
In [75]: c = "two"

In [76]: a.__hash__()
Out[76]: -261223665

In [77]: b.__hash__()
Out[77]: -261223665

In [78]: c.__hash__()
Out[78]: 323309869

In [79]: set([a,b,c])
Out[79]: set(['two', 'one'])

现在,让我们导入numpy,看看你的矩阵的哈希值是什么。

In [81]: import numpy as np
In [82]: W = np.matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
In [83]: E = np.matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

In [84]: W.__hash__()
Out[84]: 4879307

In [85]: E.__hash__()
Out[85]: 4879135

请注意,EW的哈希值不同,即使它们似乎包含相同的内容。由于它们的哈希值不同,它们将在集合中显示为不同的对象。当您执行W = E之类的作业时,名称WE实际上是指同一个对象。

如果您需要解决方法,可以存储用于构建矩阵的字符串:

In [86]: set(['1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2',
              '1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2'])
Out[86]: set(['1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2'])

答案 2 :(得分:2)

matrix__eq__中使用它们时,没有表现良好的__hash__set方法。如果要使用set使它们唯一,则需要将矩阵包装在辅助类中。像这样简单的东西应该做;

import hashlib

class MatrixWrap:
     def __init__(self, matrix):
         self.matrix = matrix
     def __hash__(self):
         return int(hashlib.sha1(self.matrix).hexdigest(), 16)
     def __eq__(self, x):
         return self.__hash__() == x.__hash__()

然后就可以了;

from numpy import *
from numpy.linalg import *

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
X = matrix('2, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrices = set()
matrices.add(MatrixWrap(W))
matrices.add(MatrixWrap(E))
matrices.add(MatrixWrap(X))

for a in matrices:
    print a.matrix

...列出您的独特矩阵。

答案 3 :(得分:0)

所有答案和评论都很好,并确定了问题,而@Joachim Isaksson确定了一个很好的解决方案。我想指出你也可以序列化常规数组并将数据转储/加载到集合中,如下所示:

import numpy as np

def arrayToTuple(arr):
    arrType = arr.dtype.str
    arrShape = arr.shape
    arrData = arr.tostring()

    return (arrType,arrShape,arrData)

def tupleToArray(tupl):
    arrType, arrShape, arrData = tupl

    return np.matrix( np.fromstring(arrData, dtype=arrType).reshape(arrShape) )
        # remove the matrix( ) wrap to return arrays instead of matrices

然后你的代码看起来像这样:

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrixTuples = set()

matrixTuples.add(arrayToTuple(W))
matrixTuples.add(arrayToTuple(E))

for mTupl in matrixTuples:
    print tupleToArray(mTupl)

这也适用于常规的bool,integer和float数组(但不是对象或字符串数​​组) - 只需删除arrayFromTuple返回的matrix()包装器。我想这些函数可能更好地命名为matrixToTuple和tupleToMatrix,但无论你是使用矩阵还是数组,它们都非常接近。