Python 使用递归的特殊嵌套列表
Python Special Nested List using Recursion
我有一个要放入嵌套列表中的函数和值列表。我希望结果是一个 LISP 样式列表(看起来接近某些 LISP 样式可执行代码的东西),我可以在以后轻松处理。
这个列表来自一个“句子”,它按单词分成一个列表——它通过首先检查数据库中的任何多词标记,将它们粘合在一起,然后将它们分开,将定义的短语(多词)保持在一起。
不在数据库中的任何单词都将被忽略。标点符号也被忽略。它只是匹配实际存储的令牌。
这让我写了一个句子,可以翻译成我以后可以处理的函数。
我们可以忽略这些是函数这一事实,只需将它们视为字符串,因为它们就是这样存储的,但是函数和参数完美地描述了用例,因为它们就是这样。
函数将是列表中的第一项,然后是同一列表中的参数。
没有参数的函数将在只有一个元素的列表中。
本身就是函数的参数将在列表中(如果有的话,还有它的参数)。
每个函数接受的参数数量是预设的,不会改变(它可以调用其他接受自己参数的函数)。
技术上应该能够无限深入,但我确信如果限制有帮助,几个级别就足够了。这是一个递归类型的问题,所以深度级别并不重要。
如果有帮助,我正在使用 Django,因此可以访问那里的任何模型方法,因为 Token 是一个模型,句子也是。
我将列表项称为“令牌”。它们可以不止一个词。它们实际上存储在数据库中。
每个 Token 可以有:symbol, val, kind
符号:在句子中搜索的漂亮格式字符串
值:列表中我们想要的东西
种类:一个整数;其他种类的参数或代码的数量
KIND_CHOICES = [ (0, 'Argless Function'), (1, '1-Arg Function'), (2, '2-Arg Function'), (3, '3-Arg Function'), (4, '4-Arg Function'), (6, 'Value'), (7, 'Ignore'), ]
让我们以这些代币为例:
("符号",'val',种类)
("Walk",'walk',1) ("To",'to',1) ("Sandwich Shop",'sandwich-shop',6) ("Order",'place_order',2) ("Toasted",'toast',1) ("Sandwich",'sandwich',6) ("Dine-In",'here',0) ("Eat",'eat',1) ("Back",'back',1) ("Home",'residence',6) ("Nap",'sleep',0) ("on the sofa",7)
这是一个例句:
Walk To the Sandwich Shop, Order your favorite Toasted Sandwich for Dine-In, Eat your Sandwich, Walk Back Home, then finally Nap on the sofa.
我将从我当前工作的清理函数中得到的第一个列表给我们:
['walk','to','sandwich-shop','place_order','toast','sandwich','here','eat','sandwich','walk','back','residence','sleep']
然后,最后(我就是做不对的部分!我错了一个,得到重复的,丢失的标记,或者错误的结构)
[['walk',['to','sandwich-shop']],['place_order',['toast','sandwich'],['here']],['eat','sandwich'],['walk',['back','residence']],['sleep']]
我的一些尝试涉及对参数使用重复的占位符字符串,以及各种 replace_or_append 实现尝试;在参数列表中插入空元素,然后使用 put_in_next_empty_spot 实现(尝试几次);以及一些带有递增索引和弹出的更简单的循环。
出于某种原因,我只是停留在这个问题上,并且可以使用一些脑力来解决看起来应该是一个非常简单的问题。
这是一次非常失败的尝试中的一些示例代码:
def nest(self, token, l, idx):
if token.is_func:
result = [token.val]
if token.arg_count:
for i in range(token.arg_count):
idx += 1
f = self.funcs.pop(idx)
t = self.get_token(f)
result = self.nest(t,result,idx)
l.append(result)
else:
l.append(token.val)
return l
def nestify(self):
nested = []
for i, s in enumerate(self.funcs):
token = self.get_token(s)
nested = self.nest(token,nested,i)
return nested
我使用了一些添加到 Token 的便捷方法来检查它的 .kind 属性(整数),获取 Token 对象等。[self.funcs] 这是第一个上面提到的功能列表(清理平面列表)。
原句:
"Walk To Sandwich Shop Dine-In Nap"
变成(这行得通,也是我们想要的):
['walk', 'to', 'sandwich-shop', 'here', 'nap']
应该变成:
[['walk', ['to', 'sandwich-shop']], ['here'], ['nap']]
但不幸的是,我得到:
['walk', ['to', ['here'], ['nap']], 'sandwich-shop']
为了帮助阐明输出的外观,当我处理整个列表时,我会说 'the first item in the list is a function'。这样,如果它是一个单项列表,它可以只调用该函数,如果它是一个多项列表,我们知道剩余的项目(或项目列表)是该函数的参数。
使用上面较长句子示例中的所需输出列表:
[['walk',['to','sandwich-shop']],['place_order',['toast','sandwich'],['here']],['eat','sandwich'],['walk',['back','residence']],['sleep']]
如果我们取第一项(列表):
['walk',['to','sandwich-shop']]
我们将处理传入一个参数的 'walk' 函数:评估函数 'to' 的结果,将参数传递给它 'sandwich-shop'.
如果我们取第二项(另一个列表):
['place_order',['toast','sandwich'],['here']]
我们调用 'place_order' 传递它想要的两个参数:第一个是计算 'toast' 函数的结果,将 'sandwich' 传递给 'toast' . 'place_order' 的第二个参数将是 calling/evaluating 'here'.
的结果
希望这是有道理的。 :)
如有任何帮助,我们将不胜感激!虽然我是新来的,但我已经阅读了发布问题的介绍,并希望提供了所需的一切。
谢谢!
欢乐
要根据参数规范构建嵌套列表,您可以将递归与 collections.deque
结合使用。通过使用传递给 nest_tokens
的 deque
的引用,您可以通过弹出“函数”所需的参数数量来就地改变标记化结果:
from collections import deque
def tokenize(s, tokens):
while s:
if (o:=[(a, b) for a, *b in tokens if s.startswith(a)]):
j, k = max(o, key=lambda x:len(x[0]))
yield k
s = s[len(j):]
else:
s = s[1:]
def nest_tokens(tokens, to_d = None):
c = 0
while tokens and (to_d is None or c < to_d):
if (n:=tokens.popleft())[1] == 6:
yield n[0] #found a value, yield result
else:
#found an argument token, yield back as list if empty, otherwise -
#recursively call "nest_tokens" on "tokens" to produce the arguments
yield [n[0]] if not n[1] else [n[0], *nest_tokens(tokens, n[1])]
c += 1
def nest_tokenized(s, tokens, choice):
c = dict(choice)
t = [(*i, l) for i in tokenize(s, tokens) if (l:=c.get(i[-1])) != 'Ignore']
return list(nest_tokens(deque(t)))
KIND_CHOICES = [(0, 'Argless Function'), (1, '1-Arg Function'), (2, '2-Arg Function'), (3, '3-Arg Function'), (4, '4-Arg Function'), (6, 'Value'), (7, 'Ignore')]
tokens = [("Walk",'walk',1), ("To",'to',1), ("Sandwich Shop",'sandwich-shop',6), ("Order",'place_order',2), ("Toasted",'toast',1), ("Sandwich",'sandwich',6), ("Dine-In",'here',0), ("Eat",'eat',1), ("Back",'back',1), ("Home",'residence',6), ("Nap",'sleep',0), ("on the sofa",7)]
s = 'Walk To the Sandwich Shop, Order your favorite Toasted Sandwich for Dine-In, Eat your Sandwich, Walk Back Home, then finally Nap on the sofa.'
s1 = "Walk To Sandwich Shop Dine-In Nap"
print(nest_tokenized(s, tokens, KIND_CHOICES))
print(nest_tokenized(s1, tokens, KIND_CHOICES))
输出:
[['walk', ['to', 'sandwich-shop']], ['place_order', ['toast', 'sandwich'], ['here']], ['eat', 'sandwich'], ['walk', ['back', 'residence']], ['sleep']]
[['walk', ['to', 'sandwich-shop']], ['here'], ['sleep']]
我有一个要放入嵌套列表中的函数和值列表。我希望结果是一个 LISP 样式列表(看起来接近某些 LISP 样式可执行代码的东西),我可以在以后轻松处理。 这个列表来自一个“句子”,它按单词分成一个列表——它通过首先检查数据库中的任何多词标记,将它们粘合在一起,然后将它们分开,将定义的短语(多词)保持在一起。 不在数据库中的任何单词都将被忽略。标点符号也被忽略。它只是匹配实际存储的令牌。 这让我写了一个句子,可以翻译成我以后可以处理的函数。 我们可以忽略这些是函数这一事实,只需将它们视为字符串,因为它们就是这样存储的,但是函数和参数完美地描述了用例,因为它们就是这样。 函数将是列表中的第一项,然后是同一列表中的参数。 没有参数的函数将在只有一个元素的列表中。 本身就是函数的参数将在列表中(如果有的话,还有它的参数)。 每个函数接受的参数数量是预设的,不会改变(它可以调用其他接受自己参数的函数)。 技术上应该能够无限深入,但我确信如果限制有帮助,几个级别就足够了。这是一个递归类型的问题,所以深度级别并不重要。 如果有帮助,我正在使用 Django,因此可以访问那里的任何模型方法,因为 Token 是一个模型,句子也是。
我将列表项称为“令牌”。它们可以不止一个词。它们实际上存储在数据库中。 每个 Token 可以有:symbol, val, kind 符号:在句子中搜索的漂亮格式字符串 值:列表中我们想要的东西 种类:一个整数;其他种类的参数或代码的数量
KIND_CHOICES = [ (0, 'Argless Function'), (1, '1-Arg Function'), (2, '2-Arg Function'), (3, '3-Arg Function'), (4, '4-Arg Function'), (6, 'Value'), (7, 'Ignore'), ]
让我们以这些代币为例: ("符号",'val',种类)
("Walk",'walk',1) ("To",'to',1) ("Sandwich Shop",'sandwich-shop',6) ("Order",'place_order',2) ("Toasted",'toast',1) ("Sandwich",'sandwich',6) ("Dine-In",'here',0) ("Eat",'eat',1) ("Back",'back',1) ("Home",'residence',6) ("Nap",'sleep',0) ("on the sofa",7)
这是一个例句:
Walk To the Sandwich Shop, Order your favorite Toasted Sandwich for Dine-In, Eat your Sandwich, Walk Back Home, then finally Nap on the sofa.
我将从我当前工作的清理函数中得到的第一个列表给我们:
['walk','to','sandwich-shop','place_order','toast','sandwich','here','eat','sandwich','walk','back','residence','sleep']
然后,最后(我就是做不对的部分!我错了一个,得到重复的,丢失的标记,或者错误的结构)
[['walk',['to','sandwich-shop']],['place_order',['toast','sandwich'],['here']],['eat','sandwich'],['walk',['back','residence']],['sleep']]
我的一些尝试涉及对参数使用重复的占位符字符串,以及各种 replace_or_append 实现尝试;在参数列表中插入空元素,然后使用 put_in_next_empty_spot 实现(尝试几次);以及一些带有递增索引和弹出的更简单的循环。 出于某种原因,我只是停留在这个问题上,并且可以使用一些脑力来解决看起来应该是一个非常简单的问题。
这是一次非常失败的尝试中的一些示例代码:
def nest(self, token, l, idx):
if token.is_func:
result = [token.val]
if token.arg_count:
for i in range(token.arg_count):
idx += 1
f = self.funcs.pop(idx)
t = self.get_token(f)
result = self.nest(t,result,idx)
l.append(result)
else:
l.append(token.val)
return l
def nestify(self):
nested = []
for i, s in enumerate(self.funcs):
token = self.get_token(s)
nested = self.nest(token,nested,i)
return nested
我使用了一些添加到 Token 的便捷方法来检查它的 .kind 属性(整数),获取 Token 对象等。[self.funcs] 这是第一个上面提到的功能列表(清理平面列表)。
原句:
"Walk To Sandwich Shop Dine-In Nap"
变成(这行得通,也是我们想要的):
['walk', 'to', 'sandwich-shop', 'here', 'nap']
应该变成:
[['walk', ['to', 'sandwich-shop']], ['here'], ['nap']]
但不幸的是,我得到:
['walk', ['to', ['here'], ['nap']], 'sandwich-shop']
为了帮助阐明输出的外观,当我处理整个列表时,我会说 'the first item in the list is a function'。这样,如果它是一个单项列表,它可以只调用该函数,如果它是一个多项列表,我们知道剩余的项目(或项目列表)是该函数的参数。
使用上面较长句子示例中的所需输出列表:
[['walk',['to','sandwich-shop']],['place_order',['toast','sandwich'],['here']],['eat','sandwich'],['walk',['back','residence']],['sleep']]
如果我们取第一项(列表):
['walk',['to','sandwich-shop']]
我们将处理传入一个参数的 'walk' 函数:评估函数 'to' 的结果,将参数传递给它 'sandwich-shop'.
如果我们取第二项(另一个列表):
['place_order',['toast','sandwich'],['here']]
我们调用 'place_order' 传递它想要的两个参数:第一个是计算 'toast' 函数的结果,将 'sandwich' 传递给 'toast' . 'place_order' 的第二个参数将是 calling/evaluating 'here'.
的结果希望这是有道理的。 :)
如有任何帮助,我们将不胜感激!虽然我是新来的,但我已经阅读了发布问题的介绍,并希望提供了所需的一切。
谢谢!
欢乐
要根据参数规范构建嵌套列表,您可以将递归与 collections.deque
结合使用。通过使用传递给 nest_tokens
的 deque
的引用,您可以通过弹出“函数”所需的参数数量来就地改变标记化结果:
from collections import deque
def tokenize(s, tokens):
while s:
if (o:=[(a, b) for a, *b in tokens if s.startswith(a)]):
j, k = max(o, key=lambda x:len(x[0]))
yield k
s = s[len(j):]
else:
s = s[1:]
def nest_tokens(tokens, to_d = None):
c = 0
while tokens and (to_d is None or c < to_d):
if (n:=tokens.popleft())[1] == 6:
yield n[0] #found a value, yield result
else:
#found an argument token, yield back as list if empty, otherwise -
#recursively call "nest_tokens" on "tokens" to produce the arguments
yield [n[0]] if not n[1] else [n[0], *nest_tokens(tokens, n[1])]
c += 1
def nest_tokenized(s, tokens, choice):
c = dict(choice)
t = [(*i, l) for i in tokenize(s, tokens) if (l:=c.get(i[-1])) != 'Ignore']
return list(nest_tokens(deque(t)))
KIND_CHOICES = [(0, 'Argless Function'), (1, '1-Arg Function'), (2, '2-Arg Function'), (3, '3-Arg Function'), (4, '4-Arg Function'), (6, 'Value'), (7, 'Ignore')]
tokens = [("Walk",'walk',1), ("To",'to',1), ("Sandwich Shop",'sandwich-shop',6), ("Order",'place_order',2), ("Toasted",'toast',1), ("Sandwich",'sandwich',6), ("Dine-In",'here',0), ("Eat",'eat',1), ("Back",'back',1), ("Home",'residence',6), ("Nap",'sleep',0), ("on the sofa",7)]
s = 'Walk To the Sandwich Shop, Order your favorite Toasted Sandwich for Dine-In, Eat your Sandwich, Walk Back Home, then finally Nap on the sofa.'
s1 = "Walk To Sandwich Shop Dine-In Nap"
print(nest_tokenized(s, tokens, KIND_CHOICES))
print(nest_tokenized(s1, tokens, KIND_CHOICES))
输出:
[['walk', ['to', 'sandwich-shop']], ['place_order', ['toast', 'sandwich'], ['here']], ['eat', 'sandwich'], ['walk', ['back', 'residence']], ['sleep']]
[['walk', ['to', 'sandwich-shop']], ['here'], ['sleep']]