使用set作为对iterable重新排序的方法

2024-04-28 23:24:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个元组ab,还有一个字典d

a=('C', 'G')
b=('G', 'C') 
d={('G', 'C'): 'T'}

我希望d[a]d[b]返回'T'

为此,我使用了set(),因为我认为set()是在固定iterable对象元素的顺序(并删除重复项,但我不关心这一点)

所以我做了:

tuple(set(a)) in d  # return True
tuple(set(b)) in d  # return True
# I did tuple(set()) because set() alone is not hashable and so cannot be used directly

这是有效的,直到它不起作用。因此,我比有时更容易发现

set(('C', 'G'))
{'C', 'G'}

但有时情况并非如此

set(('C', 'G'))
{'G', 'C'}

我知道set()按照它想要的顺序对元素进行排序,但我希望对于给定的元素集,顺序总是相同的

因此,我的问题是:

  • 为什么不是这样
  • 如何解决最初的问题

Tags: 对象intrue元素return字典顺序iterable
3条回答

只要在需要索引dict时使用排序的元组即可:

a = ('C', 'G')
b = ('G', 'C')
d = {tuple(sorted(a)): 'T'}
for tup in [a, b]:
   print( tup, d[tuple(sorted(tup))] )

该集合建立在一些数据结构之上,提供了有效的成员检查。结果是Python在实例化此结构时丢失了代码中指定的原始顺序

如果您真的只有两个标签,我可能会显式地指定这两个值

a=('C', 'G')
b=('G', 'C') 
d={a: 'T', b: 'T'}

要解决此问题的更大版本,需要分别设置这两个订单的值。对于更大的问题,我将使用带有双循环的理解

lbls = ['a', 'b', 'c']
{(f, s):'T' for f in lbls for s in lbls if f != s}

一种解决方案是通过对键进行排序来规范化键。当我们查找时,我们也会在查找之前对键进行排序

import collections.abc

def _normalize(key):
    """ Normalize a key (tuple) by sorting """
    key = tuple(sorted(key))
    return key

class TupleKeyDict(collections.abc.MutableMapping):
    def __init__(self, *args, **kwargs):
        temp_dict = dict(*args, **kwargs)
        self.dict = {
            _normalize(key): value
            for key, value in temp_dict.items()
        }

    def __getitem__(self, key):
        value = self.dict[_normalize(key)]
        return value

    def __setitem__(self, key, value):
        self.dict[_normalize(key)] = value

    def __delitem__(self, key):
        del self.dict[_normalize(key)]

    def __iter__(self):
        return iter(self.dict)

    def __len__(self):
        return len(self.dict)

    def __repr__(self):
        return repr(self.dict)
>>> tkd = TupleKeyDict(d)
>>> tkd
{('C', 'G'): 'T'}

>>> tkd['C', 'G']
'T'

>>> tkd['G', 'C']
'T'

>>> tkd.get(('X', 'Y')) is None
True

>>> tkd['X', 'C'] = 'cx'
>>> tkd['C', 'X']
'cx'

讨论

在集合是可变的(可变的)之前,我们不能使用集合作为键,因此不需要常量散列作为键。我的方法是创建一个专门的字典,其中键是经过排序的元组,这使得查找更容易

__init__方法接受可以传递到dict()的所有内容。__repr__方法有助于调试。所有其他方法都可以满足collections.abc.MutableMapping要求

相关问题 更多 >