Fun with enumerators, part 6 - generators
[Part 1 - Introduction, Part 2 - Additional enumerators, Part 3 - Parameterized enumerators, Part 4 - External enumerators, Part 5 - Class helper enumerators.] This was a long and interesting trip but it has to end some day. And it will end today. Just one last small topic to cover ... in Part 4 I mentioned that we could abuse enumerators to the point where they are not working on any external structure. My example for such generator which is providing its own enumeration data was for i in Fibonacci(10) do and I promised to show you how to write it. Again, we will start with a 'standard' enumerator factory, the one that we used a lot in parts 4 and 5. IEnumFibonacciFactory = interface Enumerator is slightly trickier this time - it prepares requested data in the constructor and uses MoveNext to move over this data. TEnumFibonacci = class Test code follows the well-learned pattern. procedure TfrmFunWithEnumerators.btnFibonacciClick(Sender: TObject); ![]() And now it really is a time to say goodbye. At least to this series - I intend to write many more blog entries. It was an interesting experience for me and I hope an interesting reading for you, dear reader. If you liked it, tell that to others so that they may enjoy it too. [A full source code of the demo program including all enumerators is available at http://17slon.com/blogs/gabr/files/FunWithEnumerators.zip] Labels: Delphi, enumerators, programming, source code |
9 Comments:
It would be nice to a have a article which contains all blog article in one article
Are you sure? It would be rather lenghty.
Truth is, I'm a magazine writer in first place and blogger only in second. If 'Fun with enumerators' would be a magazine article, each post with be written under one subheading of this article. But on the web, short form is better - or at least I think it is.
What if I combine all posts into one PDF file?
What do other readers think?
Usually I avoid heavy PDF when Googling for technical information.
But I aggree that navigation in a blog is not always optimal.
May be publishing somme part in i.e "Torry's Delphi Pages tips" or other sites may help to advertise your very didactic topic on enumerator.
On the article debate - personally, I think the blog form is perfect for this sort of thing.
That said, just on the code - in the current sort of case, do you actually need a separate factory class? At least, would the following work? (I don't have D2006/7 to check):
IFibonacciEnum = interface
function GetCurrent: Integer;
function MoveNext: Boolean;
property Current: Integer read GetCurrent;
end;
IGetFibonacciEnum = interface
function GetEnumerator: IFibonacciEnum;
end;
TFibonacciEnum = class(TInterfacedObject, IFibonacciEnum, IGetFibonacciEnum)
private
FFibArray: array of Integer;
FIndex: Integer;
protected
function GetEnumerator: IFibonacciEnum;
function GetCurrent: Integer;
function MoveNext: Boolean;
public
constructor Create(UpperBound: Integer);
end;
function TFibonacciEnum.GetEnumerator: IFibonacciEnum;
begin
Result := Self;
end;
//...rest of your code for Create, GetCurrent and MoveNext
function Fibonacci(UpperBound: Integer): IGetFibonacciEnum;
begin
Result := TFibonacciEnum.Create(UpperBound);
end;
Good idea! Of course the enumerator can be its own factory.
I tested your code in BDS 2006 and it works fine.
Hi,
I've read all of your posting here with enumerators and I like it very much. I was not aware that for..in..do is possible.
Anyway, may I ask for help? I've existing code which I would like to enhance using your tips but before starting to rebuild everything I would like to get some opinion. I've shorten the coding and remove some of the properties but the main purpose is visible, I guess:
TPWCNoticeItem = class(TCollectionItem)
private
public
property NoticeID : TPWCId read FId write FId;
TPWCNoticeList = class(TCollection)
private
function Get(IDX : Integer): TPWCNoticeItem;
procedure Put(IDX: Integer; const ITEM : TPWCNoticeItem);
public
constructor Create;
function Add : TPWCNoticeItem;
property Info[IDX : Integer] : TPWCNoticeItem read Get write Put; default;
destructor Destroy; override;
end;
So where would you start to rebuild this coding or better is it even possible?
Perhaps you could give me a starting point? It must not be a complete coding but some insights would be really helpful.
Thanks,
Michael
I assume you want to iterate over TPWCNoticeList and return TPWCNoticeItems? IOW, you want to do this:
var
item: TPWCNoticeItem;
list: TPWCNoticeList;
// create and fill the 'list' somehow
for item in list do
// do something with item
?
First you have to add a public GetEnumerator function to the TPWCNoticeList class. It must return some class responsible for enumeration (TPWCNoticeListEnumerator, for example).
Then you have to create this TPWCNoticeListEnumerator class and implement MoveNext, GetCurrent and Current in it - just like in all my examples.
GetEnumerator would create a new instance of the TPWCNoticeListEnumerator class while passing 'Self' to the constructor. TPWCNoticeListEnumerator would store this reference to the TPWCNoticeList class so it can be used for enumeration.
You can check how the enumerator for TGpIntegerList is implemented in my GpLists unit.
Thanks for this reply and I got this running w/o any further problems.
Do you know if I can use enumarations/iterations this way, too:
for i := NoticeList.Items.Count -1 downto 0 do [something]
As the help does not mention it, I guess it is not possible at all, right?
Cu,
Michael
If I understand correctly, you want to write enumerator that will walk through your list in reverse order?
No problems here - just initialize your enumeration class (TPWCNoticeListEnumerator) to the end of the list and then proceed towards beginning in MoveNext. I did something very similar in Part 4.
If you need both enumerators - one forward and one reverse - implement the latter via additional property, as I did in Part 2.
Post a Comment
Links to this post:
Create a Link
<< Home