虽然我很想在python中解决这个问题,但我仍然坚持使用Delphi。我有嵌套列表(实际上是嵌套列表作为属性的对象,但是从来没有),我希望以生成器方式迭代它们。也就是说,我想编写一个Next函数,它给出了嵌套列表描述的树叶中的下一个项目。
例如,假设我有
[[1,2,3],[4,5],[],[6],[7,8]]
我希望连续8次调用Next()返回1..8。
如何在没有产量和生成器的语言中执行此操作?
请注意,嵌套的深度是固定的(在此示例中为2,在现实生活中为4),但欢迎解决更深入变化的更一般情况的答案。
编辑:对不起,我应该提到,这是Delphi 2007。答案 0 :(得分:2)
如果您正在使用任何具有内置枚举器的Delphi列表,则可以通过一点递归轻松完成。您的基本列表是一个数字列表,如TList<integer>
。然后,您将嵌套列表实现为TList<TList<integer>>
。 (我假设您有Delphi 2009或2010.如果没有,它会变得有点棘手。)
您需要的是使您自己的专用列表类来自TList<T>
,并为其添加虚拟Next()函数,并为列表的枚举器添加字段。设置for..in循环时,编译器会在内部使用枚举器,但您可以手动运行它们。 Next()函数创建枚举器(如果尚未分配)并将其放入字段中,然后在其上调用MoveNext()。如果成功,请拨打GetCurrent并获取您的号码。否则,你已经完成了。 FreeAndNil枚举器,并向调用函数发出信号,告知你没有任何东西可以返回。可能最简单的方法是在Next()中放置一个 var 布尔参数,返回调用MoveNext的结果,并让调用函数检查其值。
对于较高的列表,它有点复杂,但并不多。从您刚刚设置的泛型类下降,并覆盖Next()。这个将获得一个枚举器,它枚举它所包含的列表,并返回FEnumerator.GetCurrent.Next()
的值,直到该子列表用尽,然后在其枚举器上调用MoveNext。
这适用于任何深度的嵌套列表。只是不要尝试制作包含数字和列表的列表。
答案 1 :(得分:0)
方法1:“分层列表”是树,使用(或写入)树/ treenode类,并对其值进行简单的深度优先搜索。
方法2:显式地为您的分层列表类型编写深度优先搜索:
TEnumerator = RECORD
private
FStack : Stack of TNestedList; //a stack, holding which level of the tree you are exploring
FIndexStack : Stack of Integer; //a twin stack, holding the index of the child you are exploring at each layer
public
Init( AList : TNestedList );
Next( var AVal : Integer ) : boolean;
end;
procedure TEnumerator.Init( AList );
begin
SetLength(FStack, 1);
FStack[0] := AList;
SetLength( FIndexStack, 1 );
FIndexStack[0] := 0;
_GoToNextValue();
end;
procedure TEnumerator._GoToNextValue();
begin
while FStack.notEmpty()
and FIndexStack.last > FStack.last.length do
begin
//we have finished exploring FStack.last, we need to explore its next sibling :
//pop FStack.last :
FIndexStack.pop;
FStack.pop;
//go to next sibling :
FIndexStack.last := FIndexStack.last + 1;
end;
//nothing left to explore :
if FStack.empty then Exit;
//else :
// dig through the layers of list until you reach a value
while FStack.last.isAList() do
begin
FStack.push( FStack.last[ FIndexStack.last ] );
FIndexStack.push( 0 );
end;
end;
function Next( var AVal : Integer ) : boolean;
begin
_GoToNextValue();
Result := FStack.notEmpty();
if Result then
begin
AVal := FStack.last[ FIndexStack.last ];
FIndexSatck.last := FIndexSatck.last + 1;
end;
end;
你基本上明确地做了“yield”会做什么(即:保存调用堆栈的“冻结副本”,返回当前值)
用法:
LEnum : TEnumerator;
LEnum.Init( myList );
while LEnum.Next( LVal ) do
begin
<do something>
end;
答案 2 :(得分:0)
为了解决这个问题,我最终制作了一个平面的索引列表并记住了我的位置:(在pythonesque中,因为它更短)
class Nested:
nestedList = [[1,2,3],[4,5],[],[6],[7,8]]
positions = []
curr = 0
def Setup:
for a in nestedList:
for b in a:
positions.add((a,b))
def Next:
p = positions[curr]
curr += 1
return nestedList[p[0]][p[1]]
显然我的列表在迭代期间不会改变,或者这可能不起作用......