【问题标题】:How to collapse an IEnumerable of an IEnumerable to a single IEnumerable?如何将 IEnumerable 的 IEnumerable 折叠为单个 IEnumerable?
【发布时间】:2016-08-03 11:31:54
【问题描述】:
function TSomething.Concat<T>(const E: IEnumerable<IEnumerable<T>>): IEnumerable<T>;
begin
  Result := TConcatIterator<T>.Create(E) as IEnumerable<T>;
end;

这不会编译,因为TConcatIterator&lt;T&gt; 只能连接两个可枚举,但我需要的是一个连接可枚举的可枚举的迭代器。

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 中实现这个?

【问题讨论】:

    标签: delphi ienumerable delphi-xe7 spring4d


    【解决方案1】:

    由于 Spring4D 集合是根据 .Net 中的集合建模的,因此您要查找的操作/方法称为 SelectMany

    在 1.2 中,我们在 TEnumerable 类型中有一个静态方法,因此代码如下所示:

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

    但是这有点冗长,因此您可以轻松编写一个方法来处理将IEnumerable&lt;IEnumerable&lt;T&gt;&gt; 展平为IEnumerable&lt;T&gt; 的特殊情况:

    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 操作被延迟执行和惰性求值。

    【讨论】:

    • 我刚刚发现在 Haskell 中 SelectMany 对应于 concatMap=&lt;&lt; (bind) (在 [] monad 中),这真的很酷。
    【解决方案2】:

    严格(=非惰性)版本可能如下所示:

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多