2016-08-03 49 views
1

Das kompiliert nicht, weil TConcatIterator<T> kann nur zwei Enumerables concat, aber was ich brauche ist ein Iterator, der ein Enumerable von Enumerables concats.Wie wird ein IEnumerable eines IEnumerable auf einen einzelnen IEnumerable reduziert?

Haskell hat die concat Funktion, das dies tut:

concat [[1, 2, 3], [4,5]] => [1, 2, 3, 4, 5] 

Die Delphi-Version würde wie folgt aussehen:

class function TForm1.Concat<T>(
    const AEnumerable: IEnumerable<IEnumerable<T>>): IEnumerable<T>; 
begin 
    // ??? 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    InnerList1: IList<Integer>; 
    InnerList2: IList<Integer>; 
    OuterList: IList<IEnumerable<Integer>>; 
    Concated: IEnumerable<Integer>; 
begin 
    InnerList1 := TCollections.CreateList<Integer>([1, 2, 3]); 
    InnerList2 := TCollections.CreateList<Integer>([4, 5]); 
    OuterList := TCollections.CreateList<IEnumerable<Integer>>([InnerList1, InnerList2]); 
    Concated := Concat<Integer>(OuterList); 
end; 

Wie kann ich implementieren diese in spring4d?

Antwort

3

Da die Spring4D Sammlungen nach den in .Net modelliert die Operation/Methode Sie suchen, SelectMany genannt wird.

In 1.2 haben wir eine statische Methode für den in dem TEnumerable Typ so dass der Code so aussehen würde:

Concated := TEnumerable.SelectMany<IEnumerable<Integer>, Integer>(OuterList, 
    function(x: IEnumerable<Integer>): IEnumerable<Integer> 
    begin 
    Result := x; 
    end); 

jedoch dies ein wenig ausführlich ist, so dass Sie leicht, ein Verfahren schreiben den Sonderfall zu behandeln Abflachung eine IEnumerable<IEnumerable<T>> auf ein IEnumerable<T>:

type 
    TEnumerableHelper = class helper for TEnumerable 
    class function SelectMany<T>(const source: IEnumerable<IEnumerable<T>>): IEnumerable<T>; overload; static; 
    end; 

class function TEnumerableHelper.SelectMany<T>(
    const source: IEnumerable<IEnumerable<T>>): IEnumerable<T>; 
begin 
    Result := TSelectManyIterator<IEnumerable<T>, T>.Create(source, 
    function(x: IEnumerable<T>): IEnumerable<T> 
    begin 
     Result := x; 
    end); 
end; 

und diese verwenden nur leicht wie folgt aus:

Concated := TEnumerable.SelectMany<Integer>(OuterList); 

Die Operation SelectMany wird verzögert ausgeführt und faul ausgewertet.

+0

Ich habe gerade entdeckt, dass in Haskell 'SelectMany'' concatMap' oder '= <<' (bind) (in der [] Monade) entspricht, das ist wirklich cool. –

1

Eine strenge (= nicht faul) Version könnte wie folgt aussehen:

class function TForm1.Concat<T>(
    const AEnumerable: IEnumerable<IEnumerable<T>>): IEnumerable<T>; 
var 
    L: IList<T>; 
begin 
    L := TCollections.CreateList<T>; 
    AEnumerable.ForEach(
    procedure(const AInnerEnum: IEnumerable<T>) 
    begin 
     L.AddRange(AInnerEnum); 
    end); 
    Result := L as IEnumerable<T>; 
end;