【问题标题】:Python irregular loopPython不规则循环
【发布时间】:2016-01-23 13:02:49
【问题描述】:

我正在寻找一种优雅的“Pythonic”方式来循环遍历特定大小的组中的输入。但是组的大小会有所不同,并且在开始解析之前您不知道特定组的大小。

实际上我只关心两种尺寸的组。我有一个很大的输入序列,它们的大小大多是 X,但偶尔大小为 Y。对于这个例子,假设 X=3 和 Y=4(我的实际问题是 X=7 和 Y=8)。直到元素组的中途,我才知道它是一组大小为 X 还是大小为 Y 的元素。

在我的问题中,我正在处理输入行,但为简化起见,我将用字符进行说明。

因此,如果它是一组特定大小的组,我知道我将始终以相同的顺序获得输入。因此,例如,如果它是一个大小 X 组,我将获得类型为 [a,a,b] 的元素,但如果它是一个大小为 Y 组,我将获得类型为 [a,a,c,b] 的元素。如果它是 'a' 类型的东西,我会想以某种方式处理它,而 'b' 另一个等等。

显然,我必须在某个时候测试一个元素,以确定它是属于一类还是另一类。如上所示,我不能只检查每个元素的类型,因为可能有两个相同的序列。此外,这些组在开始时可能是相同的模式,并且仅在接近结束时不同。在这个例子中,我最早可以通过测试第三个元素来检查我是否属于 X 号或 Y 号组(查看它是“c”类型还是“b”类型)。

我有一个带有暴露索引和两个额外变量的 for 循环的解决方案,但我想知道是否有更优雅的解决方案。

这是我的代码。我已将 pass 语句放在我将根据它的类型进行实际解析的位置:

counter = 0
group = 3
for index, x in enumerate("aabaabaacbaabaacbaabaab"):
    column = index - counter;
    print(str(index) + ", " + x + ", " + str(column))

    if column == 0:
        pass
    elif column == 1:
        pass
    elif column == 2:
        if x == 'c':
            pass
        elif x == 'd':
            group = 4
    elif column == 3:
        pass

    if column + 1 == group:
        counter += group 
        group = 3

在代码示例中,输入流是aabaabaacbaabaacbaabaab,因此是以下组:

  1. aab (3)
  2. aab (3)
  3. aacb (4)
  4. aab (3)
  5. aacb (4)
  6. aab (3)
  7. aab (3)

【问题讨论】:

  • 您能否 a) 给出一个简短的问题描述和 b) 提供一个MCVE?我尝试将您的问题读了三遍,但无法破译问题是什么。
  • 基本上我正在使用我知道是两种组的输入序列。当我完成输入时,我将能够确定我是否在一种或另一种组中。虽然我有一些在我当前的解决方案中有效的东西,但我觉得额外的变量可以在 C / Java 风格的循环中使用 case 语句,但在 Python 中感觉很笨重。

标签: python


【解决方案1】:

我会使用一个生成器来收集这些组并确定每个组的大小,然后最终生成每个组:

def getGroups (iterable):
    group = []
    for item in iterable:
        group.append(item)
        if len(group) == 3 and group[2] == 'c':
            yield group
            group = []
        elif len(group) == 4 and group[2] == 'd':
            yield group
            group = []

for group in getGroups('abcabcabdcabcabdcabcabc'):
    print(group)
['a', 'b', 'c']
['a', 'b', 'c']
['a', 'b', 'd', 'c']
['a', 'b', 'c']
['a', 'b', 'd', 'c']
['a', 'b', 'c']
['a', 'b', 'c']

【讨论】:

    【解决方案2】:

    看起来你需要一个带回溯的简单自动机,例如:

    def parse(tokens, patterns):
    
        backtrack = False
        i = 0
    
        while tokens:
    
            head, tail = tokens[:i+1], tokens[i+1:]
            candidates = [p for p in patterns if p.startswith(head)]
            match = any(p == head for p in candidates)
    
            if match and (backtrack or len(candidates) == 1 or not tail):
                yield head
                tokens = tail
                backtrack = False
                i = 0
    
            elif not candidates:
                if not i or backtrack:
                    raise SyntaxError, head
                else:
                    backtrack = True
                    i -= 1
    
            elif tail:
                i += 1
    
            else:
                raise SyntaxError, head
    
    tokens = 'aabaabcaabaabcxaabxxyzaabx'
    patterns = ['aab', 'aabc', 'aabcx', 'x', 'xyz']
    
    for p in parse(tokens, patterns):
        print p
    

    【讨论】:

      【解决方案3】:

      对于您的特定示例,您可以使用正则表达式:

      >>> s="aabaabaacbaabaacbaabaab"
      >>> re.findall(r'aac?b', s)
      ['aab', 'aab', 'aacb', 'aab', 'aacb', 'aab', 'aab']
      

      如果你想要一个做同样事情的解析器,你可以这样做:

      def parser(string, patterns):
          patterns=sorted(patterns, key=len, reverse=True)
          i=0
          error=False
          while i<len(string) and not error:
              for pat in patterns:
                  j=len(pat)
                  if string[i:i+j]==pat:
                      i+=j
                      yield pat
                      break
              else:
                  error=True
      
          if error or i<len(string):
              raise SyntaxWarning, "Did not match the entire string"
      
      >>> list(parser(s, ['aab', 'aacb']))
      ['aab', 'aab', 'aacb', 'aab', 'aacb', 'aab', 'aab']
      

      【讨论】:

      • 当然,这适用于示例,但正如我所提到的,这个字符串只是说明性的;每个字符代表一行输入。真正的输入是一大串行。
      • 但是你声明你逐行处理这个输入。这是一个非常典型的正则表达式应用程序。即使您的数据是 7,但有时是 8,并且只是在某些可选的第 N 个元素中有所不同——正则表达式是一种可靠的区分方式。
      • 也许我的例子混淆了一些东西。在我的示例中,字符串旨在表示行列表。字符串中的一个字符代表一整行。我这样做只是为了简洁。据我所知,您不能一次对多组行进行正则表达式。更准确的例子是 ['alpha', 'alpha', 'beta', 'alpha', 'alpha', 'gamma', 'beta', 'alpha', 'alpha', 'beta']
      • 您也可以为该模式使用正则表达式。 Demo 您可以使用mmap 在大文件上使用正则表达式...
      猜你喜欢
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 2014-08-29
      • 2013-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多