【问题标题】:Initializing a list to a known number of elements in Python [duplicate]在Python中将列表初始化为已知数量的元素[重复]
【发布时间】:2010-10-06 00:29:05
【问题描述】:

现在我正在使用一个列表,并且期待类似:

verts = list (1000)

我应该改用数组吗?

【问题讨论】:

  • 使用预定义数量的元素初始化集合。
  • 为什么?你必须在随机位置设置元素吗?
  • 为什么?我收集了一些订单很重要的物品。你们知道它是如何完成的答案吗?史蒂夫的回复似乎是唯一的办法。
  • 我很惊讶(并为@JoanVenge 感到有点抱歉)到处乱跑的数字 cmets。在我看来,标准答案应该首先包括如何完成一项任务(无论它可能多么荒谬),然后就该问题向用户提出建议/建议。这似乎毫无意义。质疑问题的有效性可以被质疑。
  • @ShashankSawant:欢迎来到 SO。

标签: python arrays list


【解决方案1】:

我首先想到的是:

verts = [None]*1000

但是你真的需要预初始化它吗?

【讨论】:

  • 是的,这正是重点。 “过早的优化是万恶之源”只是意味着你应该在不关心性能的情况下编写代码 - 首先。如果稍后发现代码运行缓慢,然后返回并进行类似这样的优化。
  • 不,过早优化是指您尝试优化您不确定是否需要优化的代码。您不应该总是尽可能快地编写代码——其他问题,如业务目标、维护成本、编写代码的工程时间,通常更重要。
  • 请注意,除了对预分配数组进行优化之外,还有其他合法情况。可能是使用它的代码不添加元素,只是替换现有的元素,所以它更像是一个数组而不是一个列表。
  • 这种初始化 Python 数组的方式是邪恶的:a=[[]]*2; a[0].append('foo'); 现在检查 a[1],你会感到震惊。相比之下,a=[[] for k in range(2)] 工作正常。
  • 检查你的假设。例如。我目前正在通过解析日志文件并将错误放入一组箱中来分析网络错误率,目前为 4 箱 / 小时和 24 小时 / 天。一天中的小时数不会改变,如果我更改箱/小时,我将停止并重新启动程序,所以我总是想要(当前)4 * 24 = 96 个箱。对我来说(具有 C / C++ / C# / 等背景)似乎很自然地从将每个 bin 初始化为 0 开始。这是一种优化,无论是否过早?
【解决方案2】:

如果不了解问题域的更多信息,就很难回答您的问题。 除非您确定需要做更多的事情,否则初始化列表的 Pythonic 方法是:

顶点 = []

您真的看到了性能问题吗?如果是这样,性能瓶颈是什么? 不要试图解决你没有的问题。将数组动态填充到 1000 个元素的性能成本可能与您真正尝试编写的程序完全无关

如果列表中的事物总是特定的原始固定长度类型(例如 char、int、float),则数组类很有用。但是,它也不需要预初始化。

【讨论】:

  • 你没有看到重点。我只想创建一个具有预定义元素数量的列表/数组。评论我为什么需要以及如何需要是愚蠢的。我知道我在做什么。谢谢。
  • 当我说,我知道我在做什么时,我的意思是编程,而不是 python。如果我知道 python,我就不会问这个问题了,现在可以吗?
  • 你能编辑问题并解释更多上下文吗?从这个问题来看,不清楚正确答案是什么,也不清楚你知道自己在做什么。
【解决方案3】:

您应该考虑使用dict 类型而不是预初始化列表。字典查找的成本很小,与访问任意列表元素的成本相当。

当使用映射时,您可以编写:

aDict = {}
aDict[100] = fetchElement()
putElement(fetchElement(), fetchPosition(), aDict)

putElement 函数可以将项目存储在任何给定位置。而且,如果您需要检查您的集合是否包含给定索引处的元素,则编写更加 Pythonic:

if anIndex in aDict:
    print "cool!"

比:

if not myList[anIndex] is None:
    print "cool!"

因为后者假定集合中没有任何真实元素可以是None。如果发生这种情况 - 你的代码行为不端。

如果您迫切需要性能,这就是您尝试预初始化变量并编写尽可能快的代码的原因 - 更改您的语言。最快的代码不能用 Python 编写。您应该改用 C 并实现包装器以从 Python 调用您预初始化和预编译的代码。

【讨论】:

    【解决方案4】:

    你可以这样做:

    verts = list(xrange(1000))

    这将为您提供一个包含 1000 个大小的元素的列表,并且恰好使用 0-999 的值进行初始化。正如list 首先执行__len__ 来确定新列表的大小,它应该是相当有效的。

    【讨论】:

    • 在 python 3.0 之前是 range(1000);在 python 3.0 中它将是 list(range(1000))
    【解决方案5】:

    不太清楚为什么每个人都让你很难做到这一点 - 有几种情况你需要一个固定大小的初始化列表。您已经正确推断出数组在这些情况下是合理的。

    import array
    verts=array.array('i',(0,)*1000)
    

    对于非 pythonistas,(0,)*1000 术语正在创建一个包含 1000 个零的元组。逗号强制 python 将(0) 识别为一个元组,否则它将被评估为 0。

    我使用元组而不是列表,因为它们通常具有较低的开销。

    【讨论】:

    • 我猜有些人从字面上理解“过早”的优化。
    • 谢谢!这个解决方案正是我正在寻找的。分析时,列表初始化是我代码中的瓶颈,这使它快了 2 倍。
    • 遗憾的是,我还没有找到一个关于 SO 的 Python 问题的答案,它不包含一些自鸣得意的“你为什么要这样做?”——将宿舍傲慢作为标准回答.是的“社区”。
    • @mikerodent Joan 是世界上许多国家的男性名字,包括法国、西班牙和荷兰。
    • @Chris 对于西班牙当然是正确的,就我所知的 N'lands 而言。不知道法国,在那里住了很多年。如果我可以稍微修改一下我的评论,这种特别恼人的侵略语气可能是由于一些(讲英语的)“宿舍运动员”假设琼是女性。
    【解决方案6】:

    一个明显但可能不是有效的方法是

    verts = [0 for x in range(1000)]
    

    请注意,这可以很容易地扩展到二维。 例如,要获得一个 10x100 的“数组”,您可以这样做

    verts = [[0 for x in range(100)] for y in range(10)]
    

    【讨论】:

      【解决方案7】:

      想要初始化一个固定大小的数组在任何编程语言中都是完全可以接受的;这不像程序员想要在 while(true) 循环中放置一个 break 语句。相信我,特别是如果元素只是要被覆盖而不仅仅是添加/减去,就像许多动态编程算法的情况一样,你不想弄乱附加语句并检查元素是否没有被已在运行中初始化(有很多代码)。

      object = [0 for x in range(1000)]

      这将适用于程序员试图实现的目标。

      【讨论】:

      • +1。我担心如果我做正确的事情来初始化具有预定义大小的数组。你的回答让我冷静。
      【解决方案8】:

      @Steve 已经很好地回答了你的问题:

      verts = [None] * 1000
      

      警告:正如@Joachim Wuttke 指出的,列表必须使用不可变元素进行初始化。 [[]] * 1000 无法按预期工作,因为您将获得一个包含 1000 个相同列表的列表(类似于 C 中相同列表的 1000 个点的列表)。像 int、str 或 tuple 这样的不可变对象就可以了。

      替代方案

      调整列表大小很慢。以下结果并不令人惊讶:

      >>> N = 10**6
      
      >>> %timeit a = [None] * N
      100 loops, best of 3: 7.41 ms per loop
      
      >>> %timeit a = [None for x in xrange(N)]
      10 loops, best of 3: 30 ms per loop
      
      >>> %timeit a = [None for x in range(N)]
      10 loops, best of 3: 67.7 ms per loop
      
      >>> a = []
      >>> %timeit for x in xrange(N): a.append(None)
      10 loops, best of 3: 85.6 ms per loop
      

      但如果您没有非常大的列表,则调整大小不会很慢。与其使用单个元素(例如None)和固定长度来初始化列表以避免列表大小调整,不如考虑使用列表推导并直接用正确的值填充列表。例如:

      >>> %timeit a = [x**2 for x in xrange(N)]
      10 loops, best of 3: 109 ms per loop
      
      >>> def fill_list1():
          """Not too bad, but complicated code"""
          a = [None] * N
          for x in xrange(N):
              a[x] = x**2
      >>> %timeit fill_list1()
      10 loops, best of 3: 126 ms per loop
      
      >>> def fill_list2():
          """This is slow, use only for small lists"""
          a = []
          for x in xrange(N):
              a.append(x**2)
      >>> %timeit fill_list2()
      10 loops, best of 3: 177 ms per loop
      

      与 numpy 的比较

      对于庞大的数据集,numpy 或其他优化的库要快得多:

      from numpy import ndarray, zeros
      %timeit empty((N,))
      1000000 loops, best of 3: 788 ns per loop
      
      %timeit zeros((N,))
      100 loops, best of 3: 3.56 ms per loop
      

      【讨论】:

        【解决方案9】:

        这个:

         lst = [8 for i in range(9)]
        

        创建一个列表,初始化元素 8

        但是这个:

        lst = [0] * 7
        

        将创建 7 个包含一个元素的列表

        【讨论】:

        • [0] * 7 计算结果为 [0, 0, 0, 0, 0, 0, 0],这是一个包含 7 个元素的列表。或者您是在描述一些非常旧版本的 Python 的行为吗?
        • 他说的是列表包含7个元素,但是这7个元素都指向同一个内存。对这 7 个元素中的任何一个进行修改都会导致其他元素相应地发生变化。
        • 嗯,如果元素是整数,不是,对吧?我刚试过mylist = [0] * 4,然后mylist[0] = 12之后,mylist返回[12, 0, 0, 0]
        猜你喜欢
        • 1970-01-01
        • 2021-08-21
        • 2018-08-27
        • 1970-01-01
        • 2012-09-29
        • 1970-01-01
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多