【问题标题】:append to a sublist appends to every sublist附加到子列表 附加到每个子列表
【发布时间】:2012-12-20 20:40:24
【问题描述】:

我正在编写一个包含 10 个存储桶列表的简单哈希表。使用内置的hash() 计算索引,然后对表大小取模。但是,当我尝试将对象附加到该索引处的存储桶列表时,它会被附加到每个存储桶列表中。 我尝试过以不同的方式定义 add_HT,但我一直得到相同的结果。我做错了什么?

size = 10
HT = [ [] ] * size

def add_HT(data):
    index = hash(data) % size
    HT[index].append(data)

print HT

[[], [], [], [], [], [], [], [], [], []]

add_HT('hello')

[['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello'], ['hello']]

【问题讨论】:

    标签: python list append


    【解决方案1】:

    HT = [ [] ] * size 使size 指向同一个列表的指针数量。 add_HT 不是这里的问题。您需要将HT 定义为[[] for i in xrange(size)]

    【讨论】:

      【解决方案2】:

      您将HT 定义为对单个列表的十个引用。相反,像这样定义它:

      HT = [[] for _ in xrange(size)]
      

      【讨论】:

        【解决方案3】:

        这是正确的版本:

        size = 10
        HT = [ [] for x in range(size)]
        
        def add_HT(data):
            index = hash(data) % size
            HT[index].append(data)
        
        print HT
        
        add_HT('hello')
        print HT
        

        输出:

        >>> 
        [[], [], [], [], [], [], [], [], [], []]
        [[], ['hello'], [], [], [], [], [], [], [], []]
        >>>
        

        【讨论】:

          【解决方案4】:

          正如 Volatility 和 kindall 已经解释的那样,HT = [ [] ] * size 复制了 10 个相同的空 list,而不是 10 个不同的空 lists。 list 身份总是会咬新程序员——有时甚至会咬专家。

          他们已经向您展示了如何解决问题并获得 10 个不同的空lists。但是还有另一种方法可以解决这个问题。如果您可以重写您的程序以完全不改变lists,那么它们是否相同并不重要:

          def add_HT(data):
              index = hash(data) % size
              HT[index] = HT[index] + [data]
          

          现在:

          >>> add_HT('hello')
          >>> add_HT('goodbye')
          >>> HT
          [['goodbye'], ['hello'], [], [], [], [], [], [], [], []]
          

          这里发生的情况是,您每次追加时都会创建一个新存储桶,并替换旧存储桶,因此这些存储桶是不可变的。 (您可能希望将它们存储为 tuples 而不是 lists,以确保您不会意外地改变它们。)

          您可以更进一步,不仅使每个 HT[i] 不可变,而且使 HT 本身:

          def add_HT(data):
              global HT
              index = hash(data) % size
              HT = [bucket if i != index else bucket + [data] for i, bucket in enumerate(HT)]
          

          有时使事物不可变会使代码更简单,有时则更复杂。 (在这种情况下,我认为第一个不可变版本与可变版本一样简单,但第二个版本的可读性要差得多。)有时它使代码更快,有时更慢。 (在这种情况下,快速测试显示第一个速度大致相同,但第二个速度慢 50 倍,并且使用更多内存。另一方面,使用 PyPy 而不是 CPython,它们分别是 15% 和 30%较慢,分别……)但它总是更容易推理——你不必担心对象身份。除非它使事情更容易编写、更容易阅读、更快,否则你必须考虑权衡。但值得知道如何去做。

          【讨论】:

            猜你喜欢
            • 2019-03-29
            • 2014-02-14
            • 1970-01-01
            • 1970-01-01
            • 2020-04-23
            • 1970-01-01
            • 2013-06-18
            • 1970-01-01
            相关资源
            最近更新 更多