Reputation: 167
TListBox component contains a set of rows (strings). How can I get this set as a list TList ? The code examples below, do not give the desired result. (Сode does not compile)
MyList := TList<String>.Create(MyListBox);
MyList := TList<String>.Create(MyListBox.Items);
MyList := TList<String>.Create(MyListBox.Items.ToStringArray);
Is it possible to do this without using a loop or not? Thanks!
Upvotes: 2
Views: 2530
Reputation: 596206
David's answer is simple, if you do not mind an extra array being allocated to hold a temp copy of the strings being copied. If you want to reduce memory usage, especially if the list is large, a loop is better:
var
MyList: TList<String>;
I: Integer;
begin
MyList := TList<String>.Create;
try
MyList.Capacity := MyListBox.Items.Count;
for i := 0 to MyList.Capacity-1 do
MyList.Add(MyListBox.Items[I]);
...
finally
MyList.Free;
end;
end;
Alternatively:
var
MyList: TList<String>;
S: String;
begin
MyList := TList<String>.Create;
try
MyList.Capacity := MyListBox.Items.Count;
for S in MyListBox.Items do
MyList.Add(S);
...
finally
MyList.Free;
end;
end;
However, if you don't want to loop manually, so I would suggest creating a custom enumerator so you can pass the TStrings
data directly to TList<String>
and let it copy the strings for you:
type
TStringsEnumeratorWrapper = class(TEnumerator<String>)
protected
FEnum: TStringsEnumerator;
function DoGetCurrent: String; override;
function DoMoveNext: Boolean; override;
public
constructor Create(AStrings: TStrings);
destructor Destroy; override;
end;
constructor TStringsEnumeratorWrapper.Create(AStrings: TStrings);
begin
inherited Create;
FEnum := AStrings.GetEnumerator;
end;
destructor TStringsEnumeratorWrapper.Destroy;
begin
FEnum.Free;
inherited Destroy;
end;
function TStringsEnumeratorWrapper.DoGetCurrent: String;
begin
Result := FEnum.Current;
end;
function TStringsEnumeratorWrapper.DoMoveNext: Boolean;
begin
Result := FEnum.MoveNext;
end;
type
TStringsEnumerableWrapper = class(TEnumerable<String>)
protected
FStrings: TStrings;
function DoGetEnumerator: TEnumerator<T>; override;
public
constructor Create(AStrings: TStrings);
end;
constructor TStringsEnumerableWrapper.Create(AStrings: TStrings);
begin
inherited Create;
FStrings := AStrings;
end;
function TStringsEnumerableWrapper.DoGetEnumerator: TEnumerator<T>;
begin
Result := TStringsEnumeratorWrapper.Create(FStrings);
end;
var
MyList: TList<String>;
Enum: TStringsEnumerableWrapper;
begin
MyList := TList<String>.Create;
try
MyList.Capacity := MyListBox.Items.Count;
Enum := TStringsEnumerableWrapper.Create(MyListBox.Items);
try
MyList.AddRange(Enum);
finally
Enum.Free;
end;
...
finally
MyList.Free;
end;
end;
Alternatively:
type
TStringsEnumeratorWrapper = class(TObject, IEnumerator<String>)
protected
FEnum: TStringsEnumerator;
public
constructor Create(AStrings: TStrings);
destructor Destroy; override;
function GetCurrent: String;
function MoveNext: Boolean;
procedure Reset;
end;
constructor TStringsEnumeratorWrapper.Create(AStrings: TStrings);
begin
inherited Create;
FEnum := AStrings.GetEnumerator;
end;
destructor TStringsEnumeratorWrapper.Destroy;
begin
FEnum.Free;
inherited Destroy;
end;
function TStringsEnumeratorWrapper.GetCurrent: String;
begin
Result := FEnum.Current;
end;
function TStringsEnumeratorWrapper.MoveNext: Boolean;
begin
Result := FEnum.MoveNext;
end;
procedure TStringsEnumeratorWrapper.Reset;
begin
//FEnum.Reset;
end;
type
TStringsEnumerableWrapper = class(TObject, IEnumerable<String>)
protected
FStrings: TStrings;
public
constructor Create(AStrings: TStrings);
function GetEnumerator: IEnumerator<String>;
end;
constructor TStringsEnumerableWrapper.Create(AStrings: TStrings);
begin
inherited Create;
FStrings := AStrings;
end;
function TStringsEnumerableWrapper.GetEnumerator: IEnumerator<String>;
begin
Result := TStringsEnumeratorWrapper.Create(FStrings);
end;
var
MyList: TList<String>;
begin
MyList := TList<String>.Create;
try
MyList.Capacity := MyListBox.Items.Count;
MyList.AddRange(TStringsEnumerableWrapper.Create(MyListBox.Items));
...
finally
MyList.Free;
end;
end;
Granted, not as elegant as David's answer, but enumerators were designed to help make looping through list items easier (and thus allowed the creation of the for..in
loop syntax).
Upvotes: 3
Reputation: 612954
You can do this:
MyList := TList<string>.Create;
try
MyList.AddRange(MyListBox.Items.ToStringArray);
....
finally
MyList.Free;
end;
If you wanted to assign the items in the constructor you'd need an instance of TEnumerable<string>
. That's not easy to graft on to TStrings
from the outside. So I think the above code is probably the cleanest.
Upvotes: 5