【问题标题】:How to process a string into layer of sublists如何将字符串处理成子列表层
【发布时间】:2023-03-28 12:45:01
【问题描述】:

这是示例表格,我稍后会尝试用文字解释。 我有一个分解字符串的列表...

[a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a]

其中 b 是标准 1,c 是标准 2

我想把它分解成这样的列表:

[a, a, a, [b, a, a, [b, a, c], a, [b, a, a, c], a, c], a]

所以我想处理字符串,这样当我遍历它时,如果项目符合条件 1,则打开一个新列表,如果项目符合条件 2,则关闭列表并返回上一级。

我尝试过这样做,但效果不佳。

def sublist(self, l):
  for line in list:
    if not b:
    self.data.append(line)
  else:
    sublist(l[line:])       #<-----  not sure how to recurse it.

我之前在 stackoverflow 上看到过将列表分成大小相等的列表,但没有一个使用一组标准分成子列表。

我对 python 比较陌生,所以我对数据结构和迭代器工具不太熟悉。

【问题讨论】:

    标签: python list recursion sublist


    【解决方案1】:
    addlist = []
    alllists = []
    for item in mylist:
        if item == b:
           newlist = [item]
           addlist.append(newlist)
           alllists.append(addlist)
           addlist = newlist
        elif item == c:
           addlist.append(item)
           addlist = alllists.pop()
        else:
           addlist.append(item)
    

    只要您的bc 分隔符平衡,上述方法将起作用;特别是,如果您有多余的cs,您将有一个堆栈下溢。

    虽然我经常喜欢递归解决方案,但这具有使堆栈显式化的优点,在这种情况下,在我看来,这会导致更容易理解代码。

    【讨论】:

      【解决方案2】:

      下面会做:

      a, b, c = 1, 2, 3
      
      def sublist(l):
        ret = []
        while l:
          val = l.pop(0)
          if val == b:
            ret.append([val] + sublist(l))
          else:
            ret.append(val)
            if val == c: break
        return ret
      
      l = [a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a]
      print l
      print sublist(l)
      

      请注意,这有修改l 的副作用。通过复制来改变它是微不足道的。

      【讨论】:

        【解决方案3】:

        给你:

        lst = "aaabaabacabaacaca"
        
        def go(it):
            for x in it:
                if x == 'b':
                    yield [x] + list(go(it))
                else:
                    yield x
                    if x == 'c':
                        break 
        
        
        print list(go(iter(lst)))
        

        【讨论】:

        • 不错。生成器绝对简化了递归结构。
        • 请注意,这通过终止输出来处理“下溢”。这可能不是我们想要的。
        • 完全符合我的要求。谢谢。
        【解决方案4】:

        有一个堆栈:

        def parseList(inList):
            stack = [[]]
            for element in inList:
                if element == 'b':
                    stack.append([element])
                    stack[-2].append(stack[-1])
                elif element == 'c':
                    stack.pop().append(element)
                else:
                    stack[-1].append(element)
            return stack[0]
        

        如果 'c' 比 'b' 多,这将中断

        【讨论】:

        • 此解决方案不起作用,OP 问题中的示例会生成IndexError: list index out of range
        【解决方案5】:

        在真正的递归风格中,您可以执行以下操作:

        x = yourlist
        i = 0
        def lets_parse():
            global i
            fnlist = []
            while i < len(x)
                if x[i] == 'c':
                    fnlist.append(x[i])
                    i += 1
                return fnlist
                elif x[i] == 'b':
                    i += 1
                    f = lets_parse()
                    f.insert(0, 'b')
                    fnlist.append(f)
                else:
                    fnlist.append(x[i])
                    i += 1
        return fnlist
        
        print lets_parse()
        

        注意全局变量的使用。许多批评者可能会反对它,认为它是糟糕的编码风格。

        【讨论】:

        • 确实,这是一种糟糕的编码风格。在“真正的递归”中,您不需要使用全局变量,结果作为参数传递并返回递归函数的值。
        【解决方案6】:
        import ast    
        mylist = '[a, a, a, b, a, a, b, a, c, a, b, a, a, c, a, c, a]'
        mylist = mylist.replace('a','"a"')
        mylist = mylist.replace('b','["b"')
        mylist = mylist.replace('c','"c"]')
        print ast.literal_eval(mylist)
        #Output:
        ['a', 'a', 'a', ['b', 'a', 'a', ['b', 'a', 'c'], 'a', ['b', 'a', 'a', 'c'], 'a', 'c'], 'a']
        

        【讨论】:

          【解决方案7】:

          这个问题有很好的答案,我特别喜欢 thg435 的使用生成器的递归解决方案和 Marcin 的迭代解决方案,它将元素添加到引用列表中。

          我还发现一些解决方案修改输入列表或使用全局状态令人不安。恕我直言,这违背了递归解决方案的真正精神。下面是我在 Python 中尝试纯函数式递归解决方案 - 当然,有更多惯用和有效的方法来解决这个问题,但我想写一个答案,因为我会用纯函数式编程语言编写它:

          # lst: the list to be processed
          # acc: accumulated result
          # stk: temporary stack
          def process(lst, acc, stk):
              if not lst:
                  return acc
              elif lst[0] == 'b':
                  return process(lst[1:], [lst[0]], [acc] + stk)
              elif lst[0] == 'c':
                  return process(lst[1:], stk[0] + [acc + [lst[0]]], stk[1:])
              else:
                  return process(lst[1:], acc + [lst[0]], stk)
          
          lst = ['a', 'a', 'a', 'b', 'a', 'a', 'b', 'a', 'c', 'a', 'b', 'a', 'a', 'c', 'a', 'c', 'a']
          process(lst, [], [])
          > ['a', 'a', 'a', ['b', 'a', 'a', ['b', 'a', 'c'], 'a', ['b', 'a', 'a', 'c'], 'a', 'c'], 'a']
          

          需要注意的一些细节:

          • 我不使用局部变量或全局变量,只使用函数参数来跟踪状态
          • 我不使用赋值运算符
          • 没有迭代器或循环用于遍历输入列表,只有递归
          • 这是一种尾递归解决方案,尽管这在 Python 中无关
          • 仅使用表达式;避免像appendextend(返回None)这样的操作
          • 从未修改过任何列表(包括输入列表),而是根据需要创建新列表(为此使用数组切片)
          • 这是一个相当简短而优雅的解决方案,但这可能是一种主观意见:)

          【讨论】:

            猜你喜欢
            • 2019-02-25
            • 2023-02-26
            • 2012-01-02
            • 1970-01-01
            • 2012-10-23
            • 1970-01-01
            • 1970-01-01
            • 2017-06-06
            • 1970-01-01
            相关资源
            最近更新 更多