【问题标题】:How do I initialize and fill a list of lists in Python?如何在 Python 中初始化和填充列表列表?
【发布时间】:2014-04-03 10:51:32
【问题描述】:

我正在尝试将单词对象(由扫描的单词、其按字母顺序排列的版本及其长度组成)按长度排序到列表中。因此,我初始化了一个长度为 0 的列表,并在浏览输入文件时对其进行了扩展。我想在列表中创建一个列表,以便我的结果 [5] 包含长度为 5 的列表。我该怎么做?

我首先将我的列表初始化如下:

results = []

然后我逐行扫描输入文件,创建临时对象,并希望将它们放入相应的列表中:

try:    #check if there exists an array for that length
    results[lineLength]
except IndexError:  #if it doesn't, create it up to that length
    # Grow the list so that the new highest index is len(word)
    difference = len(results) - lineLength
    results.extend([] for _ in range(difference))
finally:
    results[lineLength].append(tempWordObject)  

我觉得以下至少一项需要修改

(1) 我初始化结果列表的方式 (2) 我将对象附加到列表的方式 (3) 我扩展列表的方式(虽然我认为那部分是对的)

我正在使用 Python 3.4。

编辑:

from sys import argv
main, filename = argv
file = open(filename)
for line in file:           #go through the file
    if line == '\n':        #if the line is empty (aka end of file), exit loop
        break
    lineLength = (len(line)-1)  #get the line length 
    line= line.strip('\r\n')

    if lineLength > maxL:       #keeps track of length of longest word encountered
        maxL = lineLength

    #note: I've written a mergesort algorithm in a separate area in the code and it works 
    tempAZ = mergesort(line)    #mergesort the word into alphabetical order
    tempAZ = ''.join(tempAZ)    #merges the chars back together to form a string

    tempWordObject = word(line,tempAZ,lineLength) #creates a new word object

    try:    #check if there exists an array for that length
        results[lineLength]
    except IndexError:  #if it doesn't, create it up to that length
        # Grow the list so that the new highest index is len(word)
        difference = len(results) - lineLength
        results.extend([] for _ in range(difference))
        print("lineLength: ", lineLength, "    difference:", difference)
    finally:
        results[lineLength].append(tempWordObject)    

编辑:

这是我的单词类:

class word(object): #object class

    def __init__(self, originalWord=None, azWord=None, wLength=None):
        self.originalWord = originalWord
        self.azWord = azWord
        self.wLength = wLength

编辑:

这里是对我想要实现的目标的说明:当我遍历一个(长度未知的)单词列表(长度也未知)时,我正在创建包含单词的单词对象,它按字母顺序排列版本及其长度(例如 dog、dgo、3)。当我浏览该列表时,我希望所有对象都进入另一个列表 (results[]) 中的列表,该列表由单词的长度索引。如果 results[] 不包含这样的索引(例如 3),我想扩展 results[] 并在 results[3] 中启动一个列表,其中包含单词 object(dog、dgo、3)。最后,results[] 应该包含按长度索引的单词列表。

【问题讨论】:

  • 你能举一个你的出发点的例子吗?有点不清楚你的意思
  • 快速浏览一下您的代码,您将无法处理相同长度的行。还有tempWordObject是什么?你得到了损坏的代码。
  • @wnnmaw 我已经编辑了我的帖子,现在它包含了其余的代码。这更有意义吗?
  • @Michi 也许您可以更清楚地知道您的问题是什么,以及您的限制是什么。您可能会发现this 很有用。
  • @Michi 1. 编辑问题,不要只评论 2。这很好,但是有什么问题?你有错误吗?意外的输出?如果代码有效,但你认为它可以更整洁,这属于codereview.stackexchange.com

标签: python list python-3.x


【解决方案1】:

你可以有一本字典,而不是一个列表:

d = {}

这里的键是长度,值是单词列表:

if linelength not in d:
    d[linelength] = []
d[linelength].append(tempWordObject)

您可以使用d = collections.defaultdict(list) 进一步简化。

【讨论】:

  • 我不能使用字典来完成这项任务。此外,当我输入一个 600 万字的文件时,它会导致溢出错误。
  • 溢出错误?真的??你有多少内存?
  • @gnibbler 即使在 Eclipse 中分配 1GB,它也会崩溃。没有尝试通过终端运行它。不过,我总共有 8GB。无论哪种方式,我都不允许使用 defaultdict。
【解决方案2】:

你的差异是负面的。你需要反过来减去。您还需要添加一个额外的索引,因为索引从 0 开始

difference = lineLength - len(results) + 1

事实证明,为此使用defaultdict 通常更容易

例如:

from collections import defaultdict
D = defaultdict(list)
for tempWordObject in the_file:
    D[len(tempWordObject)].append(tempWordObject)

【讨论】:

  • 是的,我知道,但我不能将它用于此作业。我正在寻找一种方法来使我当前的代码工作。编辑:另外,defaultdict 不适用于我较大的输入文件,包含大约 600 万字。
  • 谢谢,我想我在那里做的数学很差 - 现在早上太早了!
【解决方案3】:

关于您的问题的三个注意事项。

  1. 嵌套列表初始化

    您在问题标题中提到了它,尽管您最终可能不需要它。一种简单的方法是使用两个嵌套的list comprehensions

    import pprint
    
    m, n = 3, 4  # 2D: 3 rows, 4 columns
    lol = [[(j, i) for i in range(n)] for j in range(m)]
    
    pprint.pprint(lol)
    # [[(0, 0), (0, 1), (0, 2), (0, 3)],
    #  [(1, 0), (1, 1), (1, 2), (1, 3)],
    #  [(2, 0), (2, 1), (2, 2), (2, 3)]]
    
  2. 使用一些默认的数据结构

    正如其他人指出的那样,您可以使用字典。特别是,collections.defaultdict 将为您提供按需初始化:

    import collections
    
    dd = collections.defaultdict(list)
    
    for value in range(10):
        dd[value % 3].append(value)
    
    pprint.pprint(dd)
    # defaultdict(<type 'list'>, {0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]})
    
  3. 比较自定义对象

    内置的sorted 函数采用关键字参数key,可用于比较自定义对象,这些对象本身不提供排序钩子:

    import operator
    
    class Thing:
        def __init__(self, word):
            self.word = word
            self.length = len(word)
    
        def __repr__(self):
            return '<Word %s>' % self.word
    
    things = [Thing('the'), Thing('me'), Thing('them'), Thing('anybody')]
    print(sorted(things, key=lambda obj: obj.length))
    # [<Word me>, <Word the>, <Word them>, <Word anybody>] 
    

【讨论】:

  • 这个作业的目的是 (1) 尽可能高效, (2) 编写我自己的排序算法。我不能使用 defaultdict 也不能​​使用内置的排序功能。我可以在不知道字数和最长字长的情况下创建一个列表吗?
  • 我明白了。我猜defaultdict 只是为您节省了一些时间,不会被视为作弊,而如果您的任务是编写排序算法,您显然不想使用sorted。但是,鉴于您的问题描述,我会说字典适合您的特定任务,因为(a)您事先不知道最长单词的长度,并且(b)您要做的就是插入(即为 dicts 摊销 O(1) 并遍历所有键。对我来说,这似乎是一份字典工作。
  • defaultdict 被认为是作弊,实际上,我已经问过了,我不允许使用它。
  • 好的,很抱歉。如果我要分配任务,我会允许它;)-因为它确实没有什么花哨的;它只是使代码更简洁。
  • 是的,很遗憾这对我来说不是一个选择
【解决方案4】:

如果您打算使用列表(这可能不是最佳选择),我认为从一开始就创建尽可能大的列表会更容易、更清晰。也就是说,如果最长的单词是 5 个字符,那么你首先创建这个列表:

output = [None, [], [], [], [], []]

这样做的好处是您不必担心在执行过程中发现异常,但它确实要求您在开始之前了解所有单词。由于您创建了一个对象类来存储所有这些,我假设您实际上存储了所有这些,所以这应该不是问题。

您总是需要在开头使用None,以便索引匹配。一旦你有了这个,你就可以遍历你的单词列表,然后像你已经做的那样简单地将它附加到适当的列表中。

for word in wordlist:
    output[len(word)].append(word)

因此,特别是对您而言,我要做的不是存储tempWordObject,而是在您处理文件时列出这些对象的列表(wordObjList)。完成文件后,关闭句柄,然后继续进行其余的处理。

生成模板列表:

output = [None]
for i in range(maxLen):
    output.append([])

word 对象列表中填写列表

for wordObj in wordObjList:
    output[wordObj.wLength].append(wordObj.originalWord)

其他一些注意事项:

  • 您无需处理文件末尾的问题。当Python在for循环中到达文件末尾时,会自动停止迭代

  • 始终确保关闭文件。您可以使用with 构造来执行此操作(with open("file.txt", 'r') as f: for line in f:

【讨论】:

  • 这似乎是最好的解决方案。但是有一个问题:我觉得首先通过整个输入文件以获得单词的最大长度是低效的。有没有办法解决这个问题?扫描 600 万字的输入文件需要很长时间。
  • 显然忽略了这个练习的重点。也很马虎——你怎么知道最长的单词提前了多久?更好地进行防御性编程
  • @gnibbler 正如我所说,我可以先扫描整个文件并找到最长的单词,但这似乎是在浪费时间。你知道是否可以动态扩展列表列表吗?
  • @Michi,看起来你已经用maxLen跟踪了你找到的最长的单词
  • @wnnmaw 这是我用于测试目的的旧代码的一部分,很抱歉造成混淆。为了实际使用该值,我需要遍历列表两次,我正在努力避免这种情况。
【解决方案5】:

您拒绝接受建议将您的对象存储在字典中的答案。但是,您真正的问题是您想将包含扫描图像的 600 万个单词放入内存中。使用索引(或某种简单的引用)并将它们跟踪到您的结构中,然后根据它们查找您的数据。使用迭代器检索您需要的信息。

【讨论】:

  • 您能解释一下索引是什么意思吗?
  • 我会给出现的第一个单词 0,第二个单词 1,等等。我还将管理一个 CSV 文件或包含我的单词数据的自定义数据文件,第 1 行第一个单词,第二个单词的第 2 行,等等。事实上,为了使数据检索更快,我会使用 (word_lenght, index) tuples 和 lenghtNN.csv 文件。
  • 我试图避免写入文件,因为这会增加我的运行时间,但我已经考虑过了。如果它再次导致内存问题,我可能会这样做。谢谢你的澄清。
  • 欢迎您!好吧,至少将扫描的数据分开。也许其余的可以适合您存储在单词对象中的记忆。这些对象应该只存储扫描数据的路径。
  • 假设您在 10 个文件中拥有所有扫描数据。然后引用将类似于(path_to_fileN, start, end)。如果您需要该数据,您可以打开文件,找到合适的位置并阅读内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-29
  • 1970-01-01
  • 2020-04-09
相关资源
最近更新 更多