【问题标题】:Maintain count in python list comprehension在 python 列表理解中保持计数
【发布时间】:2018-10-03 00:03:32
【问题描述】:

在 Python 中,在列表理解期间是否有任何 counter 可用,就像在 for 循环的情况下一样?

用这个例子会更清楚为什么我需要一个计数器:

我希望达到以下目标:

初始列表:['p', 'q', 'r', 's']

所需列表:[(1, 'P'), (2, 'Q'), (3, 'R'), (4, 'S')]

在期望的列表中,每个元组的第一个元素都是序数。如果它只是平面列表,我可以使用zip 来实现这一点。但是,我正在处理的列表是嵌套的,三层深度(想想分层数据),它是通过列表理解生成的。

所以,我想知道在列表理解过程中是否有任何方法可以引入这些序数。如果不是,最好的解决方案是什么。

附: : 这里小写字母被转换为大写字母,但这不是问题的一部分,可以认为它只是一个数据转换。

代码:

allObj = Category.objects.all()

tree =[(_, l1.name, [(__, l2.name, [(___, l3.name) for l3 in allObj if l3.parentid == l2.categoryid]) for l2 in allObj if l2.parentid == l1.categoryid]) for l1 in allObj if l1.parentid == None]

allObj 包含来自表类别的数据,而表类别又包含以邻接表形式表示的分层数据。

我已将_ 放在需要序号的位置。请注意,该列表是嵌套的,因此每个级别都会有一个单独的计数器,由 1、2 和 3 _s 表示。

【问题讨论】:

  • 您几乎可以肯定使用 zip 来实现这一点。如果您不向我们展示您的代码,没有人可以告诉您。
  • @Marcin:我也添加了代码 sn-p。
  • 在保存在平面列表中的这个层次结构中进行计数并非易事。你应该首先建立一个真正的层次结构,然后你就可以依赖每个层次。
  • @Nobody:这个层次结构来自一个数据库表,因为它以邻接表的形式存储在那里。什么是建立真正的层次结构,你是说树?

标签: python


【解决方案1】:

最基本的案例

[(i, x) for i, x in enumerate(some_list, 1)]

使用 if 语句应用过滤器

[(i, x) for i, x in enumerate(some_list, 1) if i > 2]

或者像这样

[(i, x) for i, x in enumerate(some_list, 1) if x != 'p']

忠告

大多数情况下,您不需要这样做。相反,您只需在需要枚举的地方调用enumerate(some_list, 1),例如在for 循环中。

【讨论】:

  • 不错,我不知道 enumerate 中的第二个参数 :)
  • 9000:现在我不关注你了。根据您的回答,您知道它是自动完成的(如果您在我添加 1 作为我一开始忘记的初始值之前没有发表评论)
  • 也许更好:list(enumerate(map(str.upper, oldList), 1))。还要注意oldList,以避免使用内置名称list
  • 是的,可能是更好的解决方案。甚至认为用户询问理解。 :) 通过列表,我指的是列表而不是变量名。但你是对的,可能会令人困惑。
  • @NiclasNilsson:if 如何使用 enumerate() 在上述解决方案中发挥作用。
【解决方案2】:

当我偶然发现这个答案时,我正在寻找一些稍微不同的东西。

我的情况是根据列表理解中的条件进行计数。 以防万一它对其他人有用,这就是我解决它的方法:

import itertools counter = itertools.count(0) [(next(counter), x) for x in some_list if x != 'p']

这样,计数器只会在满足条件时递增,而不是在每次迭代时递增。

【讨论】:

    【解决方案3】:

    正如其他答案中已经显示的那样,标准库为您提供enumerate,这意味着您可能甚至不需要像这样的列表:

    [(1, 'P'), (2, 'Q'), (3, 'R'), (4, 'S')]
    

    因为每次您需要将字母与与其位置相关的数字绑定时,您只需调用enumerate
    示例:

    >>> low = ['p', 'q', 'r', 's']
    >>> upp = [c.upper() for c in low]
    >>>
    >>> for i,c in enumerate(upp, 1):
    ...     print(i,c)
    ...
    1 P
    2 Q
    3 R
    4 S
    

    这只是一个例子,也许你真的需要那种列表。

    【讨论】:

    • @user1144616:不客气! :) 我刚刚看到您更新的问题(使用代码 sn-p)。如果你必须坚持那个设计,我祝你好运,因为它很难构建,更难阅读。如果您可以重构代码,请查看networkx,也许它适合您的情况。
    【解决方案4】:

    RTM: enumerate(['p', 'q', 'r', 's'], 1) 给你一个生成器产生(1, 'p'), (2, 'q'), (3, 'r'), (4, 's'),将其转换为list 来品尝。

    【讨论】:

    • 我可以使用if 来过滤列表理解中的元素,在 enumerate() 的情况下如何发挥作用。
    • 过滤传入的序列,枚举结果:enumerate((x for x in some_sequence if is_good(x)), 1)
    • RTFM?他在原帖中没有提到enumerate,那他怎么能RTFM?
    • @Rabarberski:他可以阅读精美的手册来了解enumerate 并享受使用它。如果你认为“RTFM”这个词是粗鲁和居高临下的,我不是这个意思,这样的暗示是不存在的,如果“The New Hacker Dictionary”(nee “Jargon File”)是to be believed
    【解决方案5】:

    我猜你想要像编号所有项目这样的东西,独立于嵌套级别。 也许以下内容会有所帮助。不要忘记为每个列表理解创建一个新的number。在您的 Python 版本中,next 可能拼写为 __next__

    >>> import itertools
    >>> number = itertools.count().next
    >>> [(number(), [(number(), x + 1) for x in range(y) if x % 2]) for y in range(10) if y % 3]
    [(0, []), (1, [(2, 2)]), (3, [(4, 2), (5, 4)]), (6, [(7, 2), (8, 4)]), (9, [(10, 2), (11, 4), (12, 6)]), (13, [(14, 2), (15, 4), (16, 6), (17, 8)])]
    

    更新: 我知道每个嵌套级别都需要不同的计数器。只需使用多个计数器:

    >>> number1 = itertools.count().__next__
    >>> number2 = itertools.count().__next__
    >>> print([(number1(), [(number2(), x + 1) for x in range(y) if x % 2]) for y in range(10) if y % 3])
    [(0, []), (1, [(0, 2)]), (2, [(1, 2), (2, 4)]), (3, [(3, 2), (4, 4)]), (4, [(5, 2), (6, 4), (7, 6)]), (5, [(8, 2), (9, 4), (10, 6), (11, 8)])]
    

    即,将_ 替换为上面定义的number1(),将__ 替换为number2(),等等。而已。

    【讨论】:

    • 从 python 3.5+ 开始:例如number = itertools.count() 和 [next(number) for i in range(0, 10)]。
    【解决方案6】:
    L = ['p', 'q', 'r', 's']
    [(i + 1, x) for i, x in enumerate(L)]
    

    【讨论】:

      【解决方案7】:

      这样的东西会有帮助吗?

      i = 1
      
      y = range(10)
      
      s = [(i + y.index(x), x**2) for x in y]
      
      print s
      
      >>> [(1, 0), (2, 1), (3, 4), (4, 9), (5, 16), (6, 25), (7, 36), (8, 49), (9, 64), (10, 81)]
      

      我怀疑可能有比通过理解更好的方法来做到这一点。

      【讨论】:

        【解决方案8】:

        很棒的线程!批准的答案和后来的扩展给了我一个想法,我认为这可能会对某人有所帮助。就是这样。

        [print('{}. Key: {}, Value: {}'.format(i, k, v)) for i, (k, v) in enumerate(some_list.items(), 1)]
        

        上面可以用来得到一个漂亮的字典输出。您可以将其用于调试、记录等...哦,是的,还有一种可能性,创建一个 csv 文件,以便您的经理可以在 Excel 中打开它。经理们喜欢他们的电子表格。

        示例输出:

        1. Key: AwesomeKey1, Value: AwesomeValue1
        2. Key: AwesomeKey2, Value: AwesomeValue2
        3. Key: AwesomeKey3, Value: AwesomeValue3
        4. Key: AwesomeKey4, Value: AwesomeValue4
        5. Key: AwesomeKey5, Value: AwesomeValue5
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-08-25
          • 2020-09-05
          • 1970-01-01
          • 2012-11-12
          • 2011-08-05
          • 1970-01-01
          • 1970-01-01
          • 2020-12-03
          相关资源
          最近更新 更多