如何在Python 3中初始化并递增列表中的未定义值?

0 投票
1 回答
2749 浏览
提问于 2025-04-17 23:28

我有一个单词字典,我正在生成一些对象,这些对象包含以下内容:

(1) 原始单词(比如说 cats)

(2) 按字母顺序排列的单词(比如说 acst)

(3) 单词的长度

在不知道最长单词长度的情况下,能不能创建一个数组(在Python中叫列表),这样当我遍历字典时,可以把包含x个字符的对象放到数组的array[x]位置呢?

举个例子,当我遇到单词“a”时,就把生成的对象放到array[1]的位置。接下来,如果遇到单词aardvark,就把生成的对象放到array[8]的位置,依此类推。

我想过先创建一个大小为1的数组,然后再往里面添加,但我不太确定这样做会怎么样。

比如说,对于第一个单词a,它会被放到array[1]的位置。但是对于下一个单词aardvark,我该怎么检查或生成更多的位置,直到达到8呢?如果我往数组里添加东西,我需要给添加函数一个参数。但是,我不能随便给,因为我不想改变之前放进去的值(比如说array[1]里的'a')。

我正在为一个作业优化我的代码,所以另一种方法是,在我确定最长单词后,再遍历一次列表。不过,我觉得在我按字母顺序排列单词并创建对象时就处理这些会更好,这样就不用两次遍历这个冗长的字典了。

还有,关于语法的一个小问题:listOfStuff[x].append(y) 是不是会在listOfStuff中x位置的列表里添加y这个值,对吧?

1 个回答

1

把长度存储为字典的键,而不是列表的索引。使用defaultdict这个工具会让这件事变得很简单,你的算法看起来会像这样:

from collections import defaultdict
results = defaultdict(list)
for word in words:
   results[len(word)].append(word)

这和你第二个问题有关:listOfStuff[x].append(y)会把内容添加到listOfStuff[x]这个已经存在的列表里。如果这个位置还没有被初始化为一个(可能是空的)列表,它就不会创建一个新的。如果x不是列表的有效索引(比如说,x=3,但listOfStuff的长度只有2),你会遇到一个IndexError错误。如果这个位置存在但不是另一个列表,你可能会遇到AttributeError错误。

使用字典可以解决第一个问题——给一个不存在的字典键赋值总是有效的。使用defaultdict这个工具还可以让你读取一个不存在的键——它会在你第一次使用这个键时,插入一个默认值,这个默认值是你在创建defaultdict时指定的函数返回的(在这个例子中,我们给它的是list,所以它会调用这个函数并得到一个空列表)。


如果因为某种原因你不能使用collections模块,下一种最好的方法还是使用字典——它们有一个叫setdefault的方法,和defaultdict的工作方式类似。你可以这样使用它:

results = {}
for word in words:
     results.setdefault(len(word), []).append(word)

如你所见,setdefault需要两个参数:一个键和一个默认值。如果这个键已经存在于字典中,setdefault会像你直接访问results[key]那样返回当前的值。如果这个键不存在,它会把第二个参数插入到字典中,并返回这个值。虽然使用起来比defaultdict稍微麻烦一点,但当你的默认值是一个空列表时,它的效果是一样的(不过,如果你的默认值创建起来比较复杂,defaultdict会更好用,因为它只在需要的时候调用那个函数,而setdefault需要你提前计算好默认值)。


虽然技术上可以用嵌套列表来实现这个功能,但这样做很麻烦。你需要:

  • 检测列表是否不够大
  • 计算出列表还需要多少个元素
  • 把列表扩展到那个大小

用Python的方式来处理第一步是捕捉错误(如果没有setdefault和defaultdict,你也可以用字典来做到这一点)。整个过程看起来像这样:

results = []
for word in words:
    try:
        results[len(word)]
    except IndexError:
        # Grow the list so that the new highest index is 
        # len(word)
        new_length = len(word) + 1
        difference = len(results) - new_length
        results.extend([] for _ in range(difference))
    finally:
        results[len(word)].append(word)

还是建议你使用字典,避免这种麻烦。列表是专门为那些元素的确切数字索引在列表外部没有意义的情况优化的,而这并不符合你的需求。当你的代码需要做的事情和你使用的数据结构不匹配时,这种代码是非常常见的,尽早学习如何避免这种情况是很有必要的。

撰写回答