【问题标题】:Delphi TList<T> Copy into another TList?Delphi TList<T> 复制到另一个TList?
【发布时间】:2014-11-03 19:50:02
【问题描述】:

我想知道是否有任何安全的方法可以将 TList 元素复制到任何其他 TList 到 特定的位置和特定的长度。我应该将 list1 的元素分配给 list2 还是 有什么我不知道的功能可以更准确地处理吗?

感谢您抽出宝贵时间。

【问题讨论】:

    标签: delphi tlist


    【解决方案1】:

    我会使用AddRange 在末尾追加项目或使用InsertRange 在特定索引上插入项目。

    【讨论】:

      【解决方案2】:

      如果您的意图是REPLACE项目而不是在给定位置插入它们,那么答案是没有直接机制,迭代分配是使用的方法。

      for i := 1 to maxItems do
        dest[ insertPos + i - 1] := src[ i - 1 ];
      

      在这种情况下,您应该考虑添加的项目超出目标列表空间的情况。这是否意味着只更换“适合”的物品、添加额外物品以“腾出空间”或根本不分配任何物品(除非所有物品都适合),这是一个只有您的要求才能回答的问题。

      但是,如果您的意图是将项目 INSERT 到目标列表中,那么您可以结合使用 InsertRange()Copy() 以及由源列表维护的 的内部 数组。例如,使用 TList 的两个实例:

      var
        src, dest: TList<String>;
        insertIndex, maxItems: Integer;
      
      dest.InsertRange( insertIndex, Copy( src.List, 0, maxItems ) );
      

      要插入 整个 src 列表,您不需要使用 Copy(),但可以直接在 中引用源列表>InsertRange() 方法:

      dest.InsertRange( insertIndex, src );
      

      性能说明:

      如果源列表很大和/或添加的子项数量很少,则使用 Copy() 可能是一项昂贵的操作。然而,将项目实际插入目标列表是非常有效的,因为 InsertRange() 方法能够在单个操作中为目标列表中的新项目腾出空间,然后插入新的为他们创建的空间中的项目,因此对于要添加的大量项目,它仍然可能被证明是最有效的。

      另一种方法是逐个迭代地插入源项:

      for i := 1 to maxItems do
        dest.Insert( insertIndex, src[i - 1]);
      

      虽然这避免了复制插入的数组项,但如果目标列表很大并且要插入大量项,则迭代插入本身可能效率低下,因为必须为目标列表中的每个项单独腾出空间insert(尽管通过显式计算和预分配目标列表的 Capacity 可能会显着改善其潜在影响)。

      例如如果您将 1000 个项目列表中的 100 个项目插入到 2000 个项目列表的(确切)中间:

      InsertRange( Copy() )       Copy 100 items into an intermediate array
                                  Moves 1000 items in the dest list to make room for 2100 (total)
                                  Inserts 100 items into the 'blank' space
      
      Iterative insert            100 repetitions of:
                                     Move 1000 items in the dest list to make room for 1 more
                                     Inserts 1 item
      

      对于插入 100 个项目,InsertRange() 可能是最有效的。相比之下,如果仅从源列表中插入单个项目,则 InsertRange() 方法会产生潜在的过多开销。

      我认为应该很明显,不同的起始条件将决定这两种方法中哪一种最有效,如果性能是一个重要问题,则应该考虑。

      【讨论】:

      • ToArray 会很昂贵,特别是如果列表很大并且只需要复制几个元素。 List 属性可以避免调用 ToArray。
      • OP 清楚地意识到迭代插入项目的能力。问题是是否有现有的功能作为替代方案。迭代插入涉及多个内存副本,以便在目标列表中分别为每个项目腾出空间,如果目标很大,这本身可能非常昂贵。带有复制数组的 InsertRange() 在“builk”中插入项目。我不认为有一种“一刀切”的方法肯定是最佳的。最好了解选项。答案将更新以解释这些选项。
      • 还注意到并解决了插入项目或替换它们的问题中的歧义。以前的答案只解决了插入案例。我也更新以解决替换案例。
      • 对不起,ToArray 在这里总是出错。请改用TList&lt;T&gt;.List 并避免复制。
      • 非常正确...奖励:通过这种更改,与迭代插入大量子项相比,性能优势更大。 :)
      【解决方案3】:

      除了来自 Enny 的回答,Assign 从目标列表中复制(清除源列表的内容)。

      list1 := TList.Create();
      for val:=1 to 3 do
          list1.Add(Pointer(val));    // list1 contains {1,2,3}
      
      list2 := TList.Create();
      for val:=5 to 8 do
          list2.Add(Pointer(val));    // list2 contains {5,6,7,8}
      
      list2.Assign(list1);            // list2 now contains {1,2,3}
      list2.Assign(list1);            // list2 still contains {1,2,3}
      
      list2.Free();
      list1.Free();
      

      【讨论】:

        【解决方案4】:

        我假设这两个列表都是通用的TList&lt;T&gt;。并且您正在复制现有项目而不是扩展目的地。

        在这种情况下,我认为使用:= 进行赋值的for 循环是可行的方法。由于您正在处理一个泛型列表,因此您需要使用一个可以处理任何泛型类型T 的运算符。假设您需要支持托管类型的T,那么您无法执行简单的内存复制。这给你留下了任务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-17
          • 1970-01-01
          • 1970-01-01
          • 2011-08-13
          • 2021-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多