Python 在开始和结束关键字模式处将列表拆分为子列表
Python splitting list to sublist at start and end keyword patterns
如果我要一份清单,请说:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
字符 !
,我如何 return 给定列表:
lst = ['foo', 'bar', ['test', 'hello', 'world'], 'word']
我在为此找到解决方案时遇到了一些困难。这是我尝试过的一种方法:
def define(lst):
for index, item in enumerate(lst):
if item[0] == '!' and lst[index+2][-1] == '!':
temp = lst[index:index+3]
del lst[index+1:index+2]
lst[index] = temp
return lst
如有任何帮助,我们将不胜感激。
我会先确定你的子列表的起点和终点在哪里,然后相应地切割列表,然后删除 !
s。
def define(lst):
# First find the start and end indexes
for index, item in enumerate(lst):
if item[0] == '!':
start_index = index
if item[-1] == "!":
end_index = index+1
# Now create the new list
new_list = lst[:start_index] + [lst[start_index:end_index]] + lst[end_index:]
# And remove the !s
new_list[start_index][0] = new_list[start_index][0][1:]
new_list[start_index][-1] = new_list[start_index][-1][:-1]
return new_list
请尝试以下:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
temp =[]
isFound=False
for str in lst:
if str.startswith("!"):
temp.append(str,replace("!",""))
isFound=True
elif len(temp) and isFound and not str.endswith("!"):
temp.append(str)
elif str.endswith("!"):
temp.append(str,replace("!",""))
isFound=False
for item in temp:
lst.remove(item)
lst.append(temp)
这是一个可以处理任意嵌套列表的迭代解决方案:
def nest(lst, sep):
current_list = []
nested_lists = [current_list] # stack of nested lists
for item in lst:
if item.startswith(sep):
if item.endswith(sep):
item = item[len(sep):-len(sep)] # strip both separators
current_list.append([item])
else:
# start a new nested list and push it onto the stack
new_list = []
current_list.append(new_list)
current_list = new_list
nested_lists.append(current_list)
current_list.append(item[len(sep):]) # strip the separator
elif item.endswith(sep):
# finalize the deepest list and go up by one level
current_list.append(item[:-len(sep)]) # strip the separator
nested_lists.pop()
current_list = nested_lists[-1]
else:
current_list.append(item)
return current_list
测试运行:
>>> nest(['foo', 'bar', '!test', '!baz!', 'hello', 'world!', 'word'], '!')
['foo', 'bar', ['test', ['baz'], 'hello', 'world'], 'word']
它的工作方式是维护一堆嵌套列表。每次创建新的嵌套列表时,它都会被压入堆栈。元素总是附加到堆栈中的最后一个列表。当以“!”结尾的元素时被找到,最顶层的列表被从堆栈中移除。
我认为你应该插入数组而不是分配它。你还需要删除 index + 3
def define(lst):
for index, item in enumerate(lst):
if item[0] == '!' and lst[index+2][-1] == '!':
temp = lst[index:index+3]
del lst[index:index+3]
lst.insert(index, temp)
return lst
这是一个非常简单的实现:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
lst_tmp = [(tuple(el.split()) if ' ' in (el[0], el[-1]) else el.split()) for el in ' '.join(lst).split('!')]
lst = []
for el in lst_tmp:
if isinstance(el, tuple):
for word in el:
lst.append(word)
else:
lst.append(el)
首先我们将 lst
合并为一个 str
,然后在 '!'
上将其拆分。现在,这导致 ['foo bar ', 'test hello world', ' word']
。我们现在可以在元素的开头或结尾使用出现的空白字符来表示嵌入的 list
应该出现的位置。应该单独出现的单词被打包到tuple
中,只是为了区别于list
(s)。所有这些导致 lst_tmp
。最后要做的是将 tuple
解压缩到它们的单个元素中,这就是循环正在做的事情。
假设没有像'!foo!'
这样以!
开头和结尾的元素。
首先我们可以编写辅助谓词,例如
def is_starting_element(element):
return element.startswith('!')
def is_ending_element(element):
return element.endswith('!')
然后我们可以写generator-function(因为他们很棒)
def walk(elements):
elements = iter(elements) # making iterator from passed iterable
for position, element in enumerate(elements):
if is_starting_element(element):
yield [element[1:], *walk(elements)]
elif is_ending_element(element):
yield element[:-1]
return
else:
yield element
测试:
>>> lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
>>> list(walk(lst))
['foo', 'bar', ['test', 'hello', 'world'], 'word']
>>> lst = ['foo', 'bar', '!test', '!hello', 'world!', 'word!']
>>> list(walk(lst))
['foo', 'bar', ['test', ['hello', 'world'], 'word']]
>>> lst = ['hello!', 'world!']
>>> list(walk(lst))
['hello']
正如我们从上一个示例中看到的那样,如果关闭元素多于打开元素,则剩余的关闭元素将被忽略(这是因为我们 return
来自生成器)。因此,如果 lst
具有无效签名(开始元素和结束元素之间的差异不等于零),那么我们可能会有一些不可预测的行为。作为摆脱这种情况的一种方法,我们可以在处理之前验证给定的数据,如果数据无效则引发错误。
我们可以这样写验证器
def validate_elements(elements):
def get_sign(element):
if is_starting_element(element):
return 1
elif is_ending_element(element):
return -1
else:
return 0
signature = sum(map(get_sign, elements))
are_elements_valid = signature == 0
if not are_elements_valid:
error_message = 'Data is invalid: '
if signature > 0:
error_message += ('there are more opening elements '
'than closing ones.')
else:
error_message += ('there are more closing elements '
'than opening ones.')
raise ValueError(error_message)
测试
>>> lst = ['!hello', 'world!']
>>> validate_elements(lst) # no exception raised, data is valid
>>> lst = ['!hello', '!world']
>>> validate_elements(lst)
...
ValueError: Data is invalid: there are more opening elements than closing ones.
>>> lst = ['hello!', 'world!']
>>> validate_elements(lst)
...
ValueError: Data is invalid: there are more closing elements than opening ones.
最后我们可以像
一样编写带有验证的函数
def to_sublists(elements):
validate_elements(elements)
return list(walk(elements))
测试
>>> lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
>>> to_sublists(lst)
['foo', 'bar', ['test', 'hello', 'world'], 'word']
>>> lst = ['foo', 'bar', '!test', '!hello', 'world!', 'word!']
>>> to_sublists(lst)
['foo', 'bar', ['test', ['hello', 'world'], 'word']]
>>> lst = ['hello!', 'world!']
>>> to_sublists(lst)
...
ValueError: Data is invalid: there are more closing elements than opening ones.
编辑
如果我们想处理以 !
开头和结尾的元素,例如 '!bar!'
,我们可以使用 itertools.chain
修改 walk
函数,例如
from itertools import chain
def walk(elements):
elements = iter(elements)
for position, element in enumerate(elements):
if is_starting_element(element):
yield list(walk(chain([element[1:]], elements)))
elif is_ending_element(element):
element = element[:-1]
yield element
return
else:
yield element
我们还需要通过修改get_sign
函数来完成验证
def get_sign(element):
if is_starting_element(element):
if is_ending_element(element):
return 0
return 1
if is_ending_element(element):
return -1
return 0
测试
>>> lst = ['foo', 'bar', '!test', '!baz!', 'hello', 'world!', 'word']
>>> to_sublists(lst)
['foo', 'bar', ['test', ['baz'], 'hello', 'world'], 'word']
如果我要一份清单,请说:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
字符 !
,我如何 return 给定列表:
lst = ['foo', 'bar', ['test', 'hello', 'world'], 'word']
我在为此找到解决方案时遇到了一些困难。这是我尝试过的一种方法:
def define(lst):
for index, item in enumerate(lst):
if item[0] == '!' and lst[index+2][-1] == '!':
temp = lst[index:index+3]
del lst[index+1:index+2]
lst[index] = temp
return lst
如有任何帮助,我们将不胜感激。
我会先确定你的子列表的起点和终点在哪里,然后相应地切割列表,然后删除 !
s。
def define(lst):
# First find the start and end indexes
for index, item in enumerate(lst):
if item[0] == '!':
start_index = index
if item[-1] == "!":
end_index = index+1
# Now create the new list
new_list = lst[:start_index] + [lst[start_index:end_index]] + lst[end_index:]
# And remove the !s
new_list[start_index][0] = new_list[start_index][0][1:]
new_list[start_index][-1] = new_list[start_index][-1][:-1]
return new_list
请尝试以下:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
temp =[]
isFound=False
for str in lst:
if str.startswith("!"):
temp.append(str,replace("!",""))
isFound=True
elif len(temp) and isFound and not str.endswith("!"):
temp.append(str)
elif str.endswith("!"):
temp.append(str,replace("!",""))
isFound=False
for item in temp:
lst.remove(item)
lst.append(temp)
这是一个可以处理任意嵌套列表的迭代解决方案:
def nest(lst, sep):
current_list = []
nested_lists = [current_list] # stack of nested lists
for item in lst:
if item.startswith(sep):
if item.endswith(sep):
item = item[len(sep):-len(sep)] # strip both separators
current_list.append([item])
else:
# start a new nested list and push it onto the stack
new_list = []
current_list.append(new_list)
current_list = new_list
nested_lists.append(current_list)
current_list.append(item[len(sep):]) # strip the separator
elif item.endswith(sep):
# finalize the deepest list and go up by one level
current_list.append(item[:-len(sep)]) # strip the separator
nested_lists.pop()
current_list = nested_lists[-1]
else:
current_list.append(item)
return current_list
测试运行:
>>> nest(['foo', 'bar', '!test', '!baz!', 'hello', 'world!', 'word'], '!')
['foo', 'bar', ['test', ['baz'], 'hello', 'world'], 'word']
它的工作方式是维护一堆嵌套列表。每次创建新的嵌套列表时,它都会被压入堆栈。元素总是附加到堆栈中的最后一个列表。当以“!”结尾的元素时被找到,最顶层的列表被从堆栈中移除。
我认为你应该插入数组而不是分配它。你还需要删除 index + 3
def define(lst):
for index, item in enumerate(lst):
if item[0] == '!' and lst[index+2][-1] == '!':
temp = lst[index:index+3]
del lst[index:index+3]
lst.insert(index, temp)
return lst
这是一个非常简单的实现:
lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
lst_tmp = [(tuple(el.split()) if ' ' in (el[0], el[-1]) else el.split()) for el in ' '.join(lst).split('!')]
lst = []
for el in lst_tmp:
if isinstance(el, tuple):
for word in el:
lst.append(word)
else:
lst.append(el)
首先我们将 lst
合并为一个 str
,然后在 '!'
上将其拆分。现在,这导致 ['foo bar ', 'test hello world', ' word']
。我们现在可以在元素的开头或结尾使用出现的空白字符来表示嵌入的 list
应该出现的位置。应该单独出现的单词被打包到tuple
中,只是为了区别于list
(s)。所有这些导致 lst_tmp
。最后要做的是将 tuple
解压缩到它们的单个元素中,这就是循环正在做的事情。
假设没有像'!foo!'
这样以!
开头和结尾的元素。
首先我们可以编写辅助谓词,例如
def is_starting_element(element):
return element.startswith('!')
def is_ending_element(element):
return element.endswith('!')
然后我们可以写generator-function(因为他们很棒)
def walk(elements):
elements = iter(elements) # making iterator from passed iterable
for position, element in enumerate(elements):
if is_starting_element(element):
yield [element[1:], *walk(elements)]
elif is_ending_element(element):
yield element[:-1]
return
else:
yield element
测试:
>>> lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
>>> list(walk(lst))
['foo', 'bar', ['test', 'hello', 'world'], 'word']
>>> lst = ['foo', 'bar', '!test', '!hello', 'world!', 'word!']
>>> list(walk(lst))
['foo', 'bar', ['test', ['hello', 'world'], 'word']]
>>> lst = ['hello!', 'world!']
>>> list(walk(lst))
['hello']
正如我们从上一个示例中看到的那样,如果关闭元素多于打开元素,则剩余的关闭元素将被忽略(这是因为我们 return
来自生成器)。因此,如果 lst
具有无效签名(开始元素和结束元素之间的差异不等于零),那么我们可能会有一些不可预测的行为。作为摆脱这种情况的一种方法,我们可以在处理之前验证给定的数据,如果数据无效则引发错误。
我们可以这样写验证器
def validate_elements(elements):
def get_sign(element):
if is_starting_element(element):
return 1
elif is_ending_element(element):
return -1
else:
return 0
signature = sum(map(get_sign, elements))
are_elements_valid = signature == 0
if not are_elements_valid:
error_message = 'Data is invalid: '
if signature > 0:
error_message += ('there are more opening elements '
'than closing ones.')
else:
error_message += ('there are more closing elements '
'than opening ones.')
raise ValueError(error_message)
测试
>>> lst = ['!hello', 'world!']
>>> validate_elements(lst) # no exception raised, data is valid
>>> lst = ['!hello', '!world']
>>> validate_elements(lst)
...
ValueError: Data is invalid: there are more opening elements than closing ones.
>>> lst = ['hello!', 'world!']
>>> validate_elements(lst)
...
ValueError: Data is invalid: there are more closing elements than opening ones.
最后我们可以像
一样编写带有验证的函数def to_sublists(elements):
validate_elements(elements)
return list(walk(elements))
测试
>>> lst = ['foo', 'bar', '!test', 'hello', 'world!', 'word']
>>> to_sublists(lst)
['foo', 'bar', ['test', 'hello', 'world'], 'word']
>>> lst = ['foo', 'bar', '!test', '!hello', 'world!', 'word!']
>>> to_sublists(lst)
['foo', 'bar', ['test', ['hello', 'world'], 'word']]
>>> lst = ['hello!', 'world!']
>>> to_sublists(lst)
...
ValueError: Data is invalid: there are more closing elements than opening ones.
编辑
如果我们想处理以 !
开头和结尾的元素,例如 '!bar!'
,我们可以使用 itertools.chain
修改 walk
函数,例如
from itertools import chain
def walk(elements):
elements = iter(elements)
for position, element in enumerate(elements):
if is_starting_element(element):
yield list(walk(chain([element[1:]], elements)))
elif is_ending_element(element):
element = element[:-1]
yield element
return
else:
yield element
我们还需要通过修改get_sign
函数来完成验证
def get_sign(element):
if is_starting_element(element):
if is_ending_element(element):
return 0
return 1
if is_ending_element(element):
return -1
return 0
测试
>>> lst = ['foo', 'bar', '!test', '!baz!', 'hello', 'world!', 'word']
>>> to_sublists(lst)
['foo', 'bar', ['test', ['baz'], 'hello', 'world'], 'word']