【问题标题】:How to get the inner loop to trigger one last time after outer loop is complete外循环完成后如何让内循环最后一次触发
【发布时间】:2020-09-15 03:56:01
【问题描述】:

我有两个列表:

  • 第一个列表包含顶级名称信息;每个项目有多个描述符
  • 第二个列表包含第一个列表中项目的变体;每个项目还有多个描述符

外部(第一个)列表包含三个项目; name1name2name3。还有一个source,但我没有费心在示例中更改它以保持简单。

内部(第二个)列表包含外部列表的名称和来源,然后有自己的名称和来源。

最终结果应该是这样的:

name1 (source1)
===============
* [name1-foo1]: . "description1"
* [name1-foo2]: . "description2"
* [name1-foo3]: . "description3"

subname1 (subsource1)
---------------
* [name1-sub1-bar1]: . "description1"
* [name1-sub1-bar2]: . "description2"
* [name1-sub1-bar3]: . "description3"

subname2 (subsource1)
---------------
* [name1-sub2-bar1]: . "description1"
* [name1-sub2-bar2]: . "description2"
* [name1-sub2-bar3]: . "description3"

...

我的问题是我的外部循环寻找 namesource 中的更改作为打印标题并继续打印下一个内容的触发器。但是由于内层循环只是由change触发,所以当外层循环用完时,它不会最后一次运行内层循环来获取所有子项。

import collections

OuterRecord = collections.namedtuple('OuterRecord',
                                     'name, source, thing, level, description')
InnerRecord = collections.namedtuple('InnerRecord',
                                     'name, source, in_name, in_source, thing, level, description')

o = [
    OuterRecord('name1', 'source1', 'name1-foo1', 1, 'description1'),
    OuterRecord('name1', 'source1', 'name1-foo2', 5, 'description2'),
    OuterRecord('name1', 'source1', 'name1-foo3', 10, 'description3'),

    OuterRecord('name2', 'source1', 'name2-foo1', 1, 'description1'),
    OuterRecord('name2', 'source1', 'name2-foo2', 5, 'description2'),
    OuterRecord('name2', 'source1', 'name2-foo3', 10, 'description3'),

    OuterRecord('name3', 'source1', 'name3-foo1', 1, 'description1'),
    OuterRecord('name3', 'source1', 'name3-foo2', 5, 'description2')
]

i = [
    InnerRecord('name1', 'source1', 'subname1', 'subsource1', 'name1-sub1-bar1', 1, 'description1'),
    InnerRecord('name1', 'source1', 'subname1', 'subsource1', 'name1-sub1-bar2', 1, 'description2'),
    InnerRecord('name1', 'source1', 'subname1', 'subsource1', 'name1-sub1-bar3', 1, 'description3'),

    InnerRecord('name1', 'source1', 'subname2', 'subsource1', 'name1-sub2-bar1', 1, 'description1'),
    InnerRecord('name1', 'source1', 'subname2', 'subsource1', 'name1-sub2-bar2', 1, 'description2'),
    InnerRecord('name1', 'source1', 'subname2', 'subsource1', 'name1-sub2-bar3', 1, 'description3'),

    InnerRecord('name2', 'source1', 'subname3', 'subsource1', 'name2-sub3-bar1', 1, 'description1'),
    InnerRecord('name2', 'source1', 'subname3', 'subsource1', 'name2-sub3-bar2', 1, 'description2'),
    InnerRecord('name2', 'source1', 'subname3', 'subsource1', 'name2-sub3-bar2', 1, 'description3'),

    InnerRecord('name3', 'source1', 'subname4', 'subsource1', 'name3-sub4-bar1', 1, 'description1'),
    InnerRecord('name3', 'source1', 'subname4', 'subsource1', 'name3-sub4-bar2', 1, 'description2'),
    InnerRecord('name3', 'source1', 'subname4', 'subsource1', 'name3-sub4-bar2', 1, 'description3'),

    InnerRecord('name3', 'source1', 'subname5', 'subsource1', 'name3-sub5-bar1', 1, 'description1'),
    InnerRecord('name3', 'source1', 'subname5', 'subsource1', 'name3-sub5-bar2', 1, 'description2'),
    InnerRecord('name3', 'source1', 'subname5', 'subsource1', 'name3-sub5-bar3', 1, 'description3'),

    InnerRecord('name3', 'source1', 'subname6', 'subsource1', 'name3-sub6-bar1', 1, 'description1'),
    InnerRecord('name3', 'source1', 'subname6', 'subsource1', 'name3-sub6-bar2', 1, 'description2'),
    InnerRecord('name3', 'source1', 'subname6', 'subsource1', 'name3-sub6-bar3', 1, 'description3'),
]


def loop_over(outer_list, inner_list):
    current_outer_name = None
    current_outer_source = None
    current_inner_name = None
    current_inner_source = None

    for outer in outer_list:
        if current_outer_name is None:
            print('\n{} ({})'.format(outer.name, outer.source))
            print('=' * 15)

            current_outer_name = outer.name
            current_outer_source = outer.source

        if outer.name != current_outer_name or outer.source != current_outer_source:

            for inner in [x for x in inner_list if x.name == current_outer_name and x.source == current_outer_source]:

                if current_inner_name is None:
                    print('\n{} ({})'.format(inner.in_name, inner.in_source))
                    print('-' * 15)
                    current_inner_name = inner.in_name
                    current_inner_source = inner.in_source

                if inner.in_name != current_inner_name or inner.in_source != current_inner_source:
                    print('\n{} ({})'.format(inner.in_name, inner.in_source))
                    print('-' * 15)
                    current_inner_name = inner.in_name
                    current_inner_source = inner.in_source

                print('* [{}]: . "{}"'.format(inner.thing, inner.description))

            print('\n{} ({})'.format(outer.name, outer.source))
            print('=' * 15)
            current_outer_name = outer.name
            current_outer_source = outer.source

        print('* [{}]: . "{}"'.format(outer.thing, outer.description))


loop_over(o, i)

所以我可以在一切完成后再单独运行一次内部循环,但这闻起来很可怕。

有没有更好的方法来构建循环,以便一次性完成?

【问题讨论】:

    标签: python nested-loops


    【解决方案1】:

    您的代码的一个有趣事实是,它看起来很有价值,可以检测变化。不幸的是,最后一个值没有机会被检测到,因为循环在那里结束。


    改为使用两个指针,一个用于当前值,一个用于列表中的 下一个 值。使用这样的条件来检测下一个变化(lookahead

    for index, outer in enumerate(outer_list):
        next_outer_source = outer_list[index + 1] if index < len(outer_list) - 1 else None
    
        show_outer_header = current_outer_name != outer.name or current_outer_source != outer.source
        show_inner_values = next_outer_source is None or outer.name != next_outer_source.name or outer.source != next_outer_source.source 
    

    这是你的函数的清理副本:

    
    def loop_over(outer_list, inner_list):
        current_outer_name = None
        current_outer_source = None
        current_inner_name = None
        current_inner_source = None
        prev_outer_source = None
    
        for index, outer in enumerate(outer_list):
            next_outer_source = outer_list[index + 1] if index < len(outer_list) - 1 else None
            
            show_outer_header = current_outer_name != outer.name or current_outer_source != outer.source
            show_inner_values = next_outer_source is None or outer.name != next_outer_source.name or outer.source != next_outer_source.source
            
            # print outer header
            if show_outer_header:
                print('\n{} ({})'.format(outer.name, outer.source))
                print('=' * 15)
                current_outer_name, current_outer_source = outer.name, outer.source
    
            # print outer value
            print('* [{}]: . "{}"'.format(outer.thing, outer.description))
    
            # print inner values
            if show_inner_values:
                current_outer_name = outer.name
                current_outer_source = outer.source
    
                for inner in [x for x in inner_list if x.name == current_outer_name and x.source == current_outer_source]:
                    if current_inner_name is None:
                        print('\n{} ({})'.format(inner.in_name, inner.in_source))
                        print('-' * 15)
                        current_inner_name = inner.in_name
                        current_inner_source = inner.in_source
    
                    if inner.in_name != current_inner_name or inner.in_source != current_inner_source:
                        print('\n{} ({})'.format(inner.in_name, inner.in_source))
                        print('-' * 15)
                        current_inner_name = inner.in_name
                        current_inner_source = inner.in_source
    
                    print('* [{}]: . "{}"'.format(inner.thing, inner.description))
    
    

    输出:

    name1 (source1)
    ===============
    * [name1-foo1]: . "description1"
    * [name1-foo2]: . "description2"
    * [name1-foo3]: . "description3"
    
    subname1 (subsource1)
    ---------------
    * [name1-sub1-bar1]: . "description1"
    * [name1-sub1-bar2]: . "description2"
    * [name1-sub1-bar3]: . "description3"
    
    subname2 (subsource1)
    ---------------
    * [name1-sub2-bar1]: . "description1"
    * [name1-sub2-bar2]: . "description2"
    * [name1-sub2-bar3]: . "description3"
    
    name2 (source1)
    ===============
    * [name2-foo1]: . "description1"
    * [name2-foo2]: . "description2"
    * [name2-foo3]: . "description3"
    
    subname3 (subsource1)
    ---------------
    * [name2-sub3-bar1]: . "description1"
    * [name2-sub3-bar2]: . "description2"
    * [name2-sub3-bar2]: . "description3"
    
    name3 (source1)
    ===============
    * [name3-foo1]: . "description1"
    * [name3-foo2]: . "description2"
    
    subname4 (subsource1)
    ---------------
    * [name3-sub4-bar1]: . "description1"
    * [name3-sub4-bar2]: . "description2"
    * [name3-sub4-bar2]: . "description3"
    
    subname5 (subsource1)
    ---------------
    * [name3-sub5-bar1]: . "description1"
    * [name3-sub5-bar2]: . "description2"
    * [name3-sub5-bar3]: . "description3"
    
    subname6 (subsource1)
    ---------------
    * [name3-sub6-bar1]: . "description1"
    * [name3-sub6-bar2]: . "description2"
    * [name3-sub6-bar3]: . "description3"
    

    【讨论】:

      【解决方案2】:

      考虑到冗长的数据结构,我希望效率并不是您真正追求的,所以这似乎是一种相当简洁易读的方式来获得您需要的东西:

      def print_outer_and_inner(outer_recs, inner_recs):
          for name, source in {(o_rec.name, o_rec.source): None for o_rec in outer_recs}:
              print(f'{name} ({source})')
              print('=' * 15)
              for o_rec in outer_recs:
                  if o_rec.name == name:
                      print(f'* [{o_rec.thing}]: . "{o_rec.description}"')
              print()
              for sub_name, sub_source in {(i_rec.in_name, i_rec.in_source): None for i_rec in inner_recs}:
                  print(f'{sub_name} ({sub_source})')
                  print('-' * 15)
                  for i_rec in inner_recs:
                      if i_rec.in_name == sub_name:
                          print(f'* [{i_rec.thing}]: . "{i_rec.description}"')
                  print()
      
      
      print_outer_and_inner(o, i)
      

      主要的缺点是它会在每个列表上循环多次,但它带给你的是简洁性,并且可以说是可读性。

      【讨论】:

      • 不幸的是,该功能似乎无法正确打印。它乱序打印外部项,它们都以 2、6、1、3、4、5 的顺序显示所有 6 个子项
      • 好点,将set() 替换为{} dict 定义,实际上是相同的解决方案,但已排序。
      猜你喜欢
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      相关资源
      最近更新 更多