简体   繁体   English

Python中的递归列表切片

[英]Recursive list slicing in Python

I am working on splicing unwanted sections in a given list, and I'd like to do it recursively. 我正在拼接给定列表中不需要的部分,我想递归地进行操作。 I'm struggling to figure out the right way to delete something based off a set of tokens. 我正在努力寻找基于一组令牌删除某些内容的正确方法。 For example, if I have ['a','b','c','d','e'] , I'm trying to recursively remove from 'b' to 'd' , which would result in ['a','e'] . 例如,如果我有['a','b','c','d','e'] ,则尝试将其从'b'递归删除为'd' ,这将导致['a','e']

Here is what has gotten me the closest thus far. 到目前为止,这是使我最接近的东西。

lines = """
variable "ops_manager_private" {
  default     = false
  description = ""
}

variable "optional_ops_manager" {
  default = false
}

/******
* RDS *
*******/

variable "rds_db_username" {
  default = ""
}

variable "rds_instance_class" {
  default = ""
}

variable "rds_instance_count" {
  type    = "string"
  default = 0
}
"""

def _remove_set(target: list, start: str, stop: str, delete=False):
    if not target:
        return []
    elif target[0] == start:
        return target[0] + _remove_set(target[1:], start, stop, delete=True)
    elif delete is True:
        return _remove_set(target[1:], start, stop, delete=True)
    elif target[0] == stop:
        return target[0] + _remove_set(target[1:], start, stop, delete=False)
    else:
        return target[0] + _remove_set(target[1:], start, stop, delete=False)


if __name__ == __main__:
    results = _remove_set(lines.splitlines(), 'ops_', '}\n')    

Then I get this error: 然后我得到这个错误:

Traceback (most recent call last):
# large recursive traceback
TypeError: can only concatenate str (not "list") to str

What is the right way to recursively slice a list? 递归切片列表的正确方法是什么?

You can skip elements between the start token 'b' and end token 'd' with a loop: 您可以使用循环在开始标记“ b”和结束标记“ d”之间跳过元素:

items=['a','b','c','d','e']
result=[]
skip=False

for item in items:
    if item == 'b':
        skip = True
    elif not skip:
        result.append(item)
    elif item == 'd':
        skip = False

print(result)
# ['a', 'e']

Typically a recursive approach would look at one element and pass the rest back to the function. 通常,递归方法将查看一个元素,然后将其余元素传递回该函数。 If you do this you only need to decide whether to include the one element + the result of the recursion. 如果执行此操作,则只需确定是否要包含一个元素+递归结果。 Something like: 就像是:

def remove(arr, delete):
    ''' remove element from arr in in delete list'''
    if not arr:    # edge condition
        return arr
    n, *rest = arr 

    if n in delete:
        return remove(rest, delete)
    else:
        return [n] + remove(rest, delete)

l = ['a','b','c','d','e']

remove(l, ['d', 'b'])

You can use a generator with itertools.takehwile to yield the elements that are not between the start/stop markers: 您可以将生成器与itertools.takehwile一起使用,以产生不在开始/停止标记之间的元素:

import itertools as it

def remove(items, start, stop):
    items = iter(items)
    while True:
        yield from it.takewhile(start.__ne__, items)
        if all(x != stop for x in items):
            break

print(list(remove('abcde', 'b', 'd')))  # ['a', 'e']
print(list(remove('abcdefbghdi', 'b', 'd')))  # ['a', 'e', 'f', 'i']

For a recursive solution you can use the (list|str|tuple).index methods instead of iterating over the elements one by one: 对于递归解决方案,可以使用(list|str|tuple).index方法,而不是一个一个地迭代元素:

def remove(items, start, stop):
    try:
        i = items.index(start)
        j = items.index(stop, i)
    except ValueError:
        return items[:]
    return items[:i] + remove(items[j+1:], start, stop)

print(remove('abcde', 'b', 'd'))  # 'ae'
print(remove('abcdefbghdi', 'b', 'd'))  # 'aefi'

Note that this only deletes items from explicitly closed sections, ie no implicit closing at the end: 请注意,这只会删除显式关闭部分中的项目,即末尾不会隐式关闭:

print(remove('abc', 'b', 'd'))  # 'abc'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM