Forum > General

How to make an iterator "IN" for the for loop go backwards?

(1/2) > >>

jamie:

using generics that have enumerators in it, in the FOR loop control, how to go backwards ?

For example:

For MyObject In  MyList downto do .....

Something of that nature.

Wallaby:
You'd have to implement a custom enumerator, see this sample for delphi: https://www.thedelphigeek.com/2007/03/fun-with-enumerators-part-4-external.html

It's quite complicated, better use

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---for I := List.Count - 1 downto 0 do

You can indeed write an enumerator for it, and in this case not difficult, but you can do this, much easier:
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{\$mode delphi}uses  Generics.Collections; var  List: TList<Integer>;  Item: Integer;begin  List := TList<Integer>.Create;  try    // Populate the list with elements (you can replace Integer with your desired type T)    List.Add(1);    List.Add(2);    List.Add(3);    // Reverse the list    List.Reverse;    For item in list do     writeln(item);  finally    List.Free;  end;end.Here for in do works the same, but on the reversed list.
Will add simple enumerator example later. It is not difficult.

Warfley:
An Enumerator has two methods, get the current element (Current) and go to the next element (MoveNext). It does not know about the total state, whats the last element, or go back, etc.

The reason for this is very simple, iterators may be used on non container elements. For example you could have an infinite stream, which has no last element and then you obviously can't reverse it. Another point would be online generators, which generate a new element with each call, so it would be highly inefficient to have to store all previous values.

For example:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{\$ModeSwitch advancedrecords} type  TFibonacciEnumerator = record    First, Second: Integer;    property Current: Integer read Second;    function MoveNext: Boolean;    function GetEnumerator: TFibonacciEnumerator;  end; function TFibonacciEnumerator.MoveNext: Boolean;var  tmp: Integer;begin  tmp := First + Second;  First := Second;  Second := tmp;  Result := Second >= First;end; function TFibonacciEnumerator.GetEnumerator: TFibonacciEnumerator;begin  Result := Self;end; function Fibonacci: TFibonacciEnumerator;begin  Result.First:=0;  Result.Second:=1;end; var  i: Integer;begin  for i in Fibonacci do    WriteLn(i);end.

Warfley:
To add to this, you can easiely write a generic iterator that works with most RTL container classes:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{\$Mode Delphi}{\$ModeSwitch advancedrecords} uses Classes; type   { TReverseIterator }   TReverseIterator<T, TElement> = record  public    Container: T;    CurrentIndex: SizeInt;    function MoveNext: Boolean;    function GetEnumerator: TReverseIterator<T, TElement>;    function GetCurrent: TElement;     property Current: TElement read GetCurrent;  end; function TReverseIterator<T, TElement>.GetCurrent: TElement;begin  Result := Container[CurrentIndex];end; function TReverseIterator<T, TElement>.MoveNext: Boolean;begin  Dec(CurrentIndex);  Result := CurrentIndex >= 0;end; function TReverseIterator<T, TElement>.GetEnumerator: TReverseIterator<T, TElement>;begin  Result := Self;end; function IterReverse<T, TElement>(Container: T): TReverseIterator<T, TElement>;begin  Result.Container := Container;  Result.CurrentIndex := Container.Count;end; var  sl: TStringList;  s: String;begin  sl:=TStringList.Create;  try    sl.Add('Test1');    sl.Add('Test2');    sl.Add('Test3');    for s in IterReverse<TStringList, String>(sl) do      WriteLn(s);  finally    sl.Free;  end;  ReadLn;end.
Or to make it more comfortable to use, use a typehelper:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{ ... TReverseIterator definition from above ...} type  TMySLHelper = class helper for TStringList    function Reversed: TReverseIterator<TStringList, String>;  end;  function TMySLHelper.Reversed: TReverseIterator<TStringList, String>;begin  Result := IterReverse<TStringList, String>(Self);end; var  sl: TStringList;  s: String;begin  sl:=TStringList.Create;  try    sl.Add('Test1');    sl.Add('Test2');    sl.Add('Test3');    for s in sl.Reversed do      WriteLn(s);  finally    sl.Free;  end;  ReadLn;end.