2016-08-03 4 views
1

Это не скомпилировано, потому что TConcatIterator<T> может только конкатрировать два перечислимых числа, но мне нужен итератор, который объединяет перечислимые числа.Как свернуть IEnumerable от IEnumerable до одного IEnumerable?

Haskell имеет функцию concat, что делает это:

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

версия Delphi будет выглядеть следующим образом:

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; 

Как я могу осуществить это в spring4d?

ответ

3

Поскольку коллекции Spring4D по образцу тех, в .NET операция/метод, который вы ищете, называется SelectMany.

В версии 1.2 мы имеем статический метод, который в TEnumerable типа, так что код будет выглядеть так:

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

Однако это немного многословным, так что вы можете легко написать метод для обработки особого случая уплощение в IEnumerable<IEnumerable<T>> к 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; 

и использовать это как раз легко, как это:

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

Операция SelectMany отложена и выполнена ленивым образом.

+0

Я только что обнаружил, что в Haskell 'SelectMany' соответствует' concatMap' или '= <<' (bind) (в [] monad), это действительно здорово. –

1

Строгое (= не ленивая) версия может выглядеть следующим образом:

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; 
Смежные вопросы