【问题标题】:In what case would I use a tuple as a dictionary key?在什么情况下我会使用元组作为字典键?
【发布时间】:2010-12-28 15:48:59
【问题描述】:

我正在研究difference between lists and tuples(在 Python 中)。一个明显的问题是元组是不可变的(初始赋值后值不能更改),而列表是可变的。

文章中的一句话吸引了我:

只有不可变的元素可以用作 字典键,因此只有元组 而不是列表可以用作键。

我很难想到我想使用元组作为字典键的情况。您能否提供一个自然、高效、优雅或显而易见的解决方案的示例问题?

编辑:

感谢您的示例。到目前为止,我认为一个非常重要的应用是函数值的缓存。

【问题讨论】:

  • 您可以使用元组,但只能使用具有不可变元素的元组。如果一个元组包含一个列表(作为其元素之一),则这样的元组不能用作键。基本规则是数据(元组)必须是可散列的。

标签: python list dictionary tuples


【解决方案1】:

经典示例:您希望将点值存储为 (x, y) 的元组

【讨论】:

  • 哇。这是非常真实的。我想不出任何其他有效存储函数值的方法!如果您的函数评估起来非常昂贵,您只需执行一次,并存储点以供以后检索。 +1!谢谢!
  • 同意。此外,您在内存中处理某事的任何地方都可以使用复合键在关系数据库中处理相同的事。
  • 我现在正在实现完全相同的场景。搜索检索的效率如何?是 O(1) 还是 O(N)?
【解决方案2】:
salaries = {}
salaries[('John', 'Smith')] = 10000.0
salaries[('John', 'Parker')] = 99999.0

编辑 1 当然,您可以使用salaries['John Smith'] = whatever,但是您必须做额外的工作才能将密钥分成名字和姓氏。 pointColor[(x, y, z)] = "red" 呢,这里 tuple key 的好处更加突出。

我必须强调,这不是最佳做法。在许多情况下,您最好创建特殊的类来处理这种情况,但 Arrieta 要求提供示例,我给了她(他)。

编辑 0

顺便说一句,每个元组元素也必须是可散列的:

>>> d = {}
>>> t = (range(3), range(10, 13))
>>> d[t] = 11
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable
>>>

【讨论】:

  • 我不怎么用python,但是salary[('John Smith')] = 99998 不是有效的字典键吗?
  • 我同意你可以这样做,但我会使用具有 __init__(self,Firs,Last,Salary) 的 Employee 类对这些数据进行建模,并为列表中的每个元素创建一个实例。在这种情况下,使用 'tuple as key' 技巧对我来说似乎有点不自然。你怎么看?
  • 当然会。但是,如果您想将密钥拆分为名字和姓氏,您将不得不做额外的工作。
  • 感谢您的编辑,我认为颜色示例非常好,正如答案中提到的一般dict[tuple] = f(tuple)。顺便说一句,我是“他”:)
  • 请注意,您不需要括号,元组由逗号定义。 salaries['John', 'Smith'] = 10000.0 也可以 :)
【解决方案3】:

我经常使用元组作为dict 键,例如

  • 当我必须从多个值创建唯一键时,我会使用它们,例如

    基于first_namelast_name 键可以是 key = '%s_%s'%(first_name, last_name) 但更好的方法是key = (first_name, last_name) 因为

    1. 它更具可读性、更短且计算量更少
    2. 检索单个值更容易
    3. 最重要的是key = '%s_%s'%(first_name, last_name) 是错误的,并且可能不会为first_namelast_name 的所有值提供唯一键,例如当值包含 _
  • 缓存函数的结果

    def func(a1, b1):
        if (a1,b1) in cache: return cache[(a1,b1)]
        ...
    

【讨论】:

    【解决方案4】:

    我在按地理位置比较网络设备的应用程序中使用元组作为字典键。由于每个位置的设备名称相似,因此它提供了一种自然的方式来了解在处理多个设备时是否已经看到与该配对匹配的设备。

    seen = {}
    seen[('abc', 'lax')] = 1
    seen[('xyz', 'nyc')] = 1
    

    【讨论】:

      【解决方案5】:

      当您想显示多个元素一起形成一个键时,您可以使用元组作为键。

      例如:{(&lt;x-coordinate&gt;,&lt;y-coordinate&gt;): &lt;indicating letter&gt;}

      在这里,如果我们分别使用x-coordinatey-coordinate,我们就不会代表这一点。

      【讨论】:

        【解决方案6】:

        在机器学习和深度学习的上下文中,如果您正在对最佳超参数进行超参数搜索,那么使用元组作为键绝对是非常有用的。

        假设您正在为learning_rateregularization_factormodel_complexity 寻找最佳超参数组合。

        然后,您可以在 Python 中创建一个字典,在其中创建这些 hparams 可以作为 keys 的不同组合,并将训练算法中它们对应的权重矩阵作为 values

        hparams_hist = {}
        hparams_hist[(0.001, 0.7, 5)] = weight_matrix1
        hparams_hist[(0.0001, 0.8, 2)] = weight_matrix2
        

        进一步需要这些权重矩阵来进行实时预测。

        【讨论】:

        • 我发现自己经常这样做!很好的例子。
        【解决方案7】:
        a[("John", "Doe")] = "123 Fake Street"
        

        【讨论】:

          【解决方案8】:

          我想在排序的情况下,使用元组可能会有好处。例如,假设字典键表示一个排序字段(显然会有一个默认排序字段来防止键为None)。如果您需要多个排序字段,例如按姓氏排序,然后按名字排序,使用元组作为字典键不是一个好主意吗?

          当然,这样的想法可能用途有限,但这并不意味着它完全没用。

          【讨论】:

            【解决方案9】:

            如果您正在构建基本分析工具,则可以将其用于漏斗分析。

            例如,计算有多少人在将鼠标悬停在 text2 上后点击了 image3。

                funnels = defaultdict(int)
                funnels[('hovered_text2', 'clicked_image3')] += 1
            

            【讨论】:

              【解决方案10】:

              您可以将其用于搜索空间中某个点的近似恒定时间搜索。例如,您可以将它用于约束满足问题,其中每个元组可能包含一些约束。约束可能是 (v1.v2) 的形式,其中 color(v1)!=color(v2) 用于着色概率等。 使用元组作为字典键,您将能够在恒定时间内判断一个排列是否满足约束。

              【讨论】:

                【解决方案11】:
                def getHash(word):
                    result={}
                    for i in range(len(word)):
                        if word[i] in result:
                            result[word[i]]+=1
                        else :
                            result[word[i]]=1
                
                    return tuple (sorted((result.items())))
                
                
                def groupAnagrams(words):
                    resultHash={}
                    for i in range(len(words)):
                        s=getHash(words[i].lower())
                        #print s
                        if s in resultHash :
                            l=list(resultHash[s]) 
                            l.append(words[i])
                            resultHash[s] = l # list(resultHash[s]).append(words[i])  
                        else :
                            resultHash[s]=[words[i]] # Creating list 
                
                    return resultHash.values()
                

                【讨论】:

                  【解决方案12】:

                  我认为元组作为字典键会很好,如果我们要存储:-

                  1. 坐标系中的一些点。

                  2. 有助于在下一次迭代中标记您想要的矩阵的位置。例如:-

                    flag = {(0,1): True, (1,0) = False}

                  【讨论】:

                    猜你喜欢
                    • 2022-06-14
                    • 2020-09-25
                    • 1970-01-01
                    • 2021-12-07
                    • 1970-01-01
                    • 2010-11-28
                    • 2018-12-20
                    • 1970-01-01
                    • 2012-03-22
                    相关资源
                    最近更新 更多