如何在C#中重用列表?

时间:2018-12-15 20:34:21

标签: c# list

在开始循环之前,我声明了List <T>List<List<T>>。然后会将某些元素添加到List <T>中。条件完成后,我将List <T>添加到List<List<T>>中。此时,我需要Clear List <T>,以便可以再次使用它,但是这也删除了List<List<T>>中的元素,这是我不想发生的事情,我该怎么办?

int counter;
List<List<T>> parent= new List<List<T>>();
List<T> child= new List<T>();
for (counter = 0; counter <= group.Count - 2; counter++)
{
    // some code here
    if ( /* condition */ )
    {
        child.Add(element);
        child.Add(element2);
        parent.Add(child);
        child.Clear();
    }
}

注意:我知道解决方案之一是在循环内使用new List<T>();,但这对我来说不是一个选择。

3 个答案:

答案 0 :(得分:3)

您不能重复使用子列表。列表是类,因此是引用类型。这意味着您实际上并不将子列表对象本身存储在父列表中,而是引用了您创建的唯一子列表。结果,列表的所有位置都指向相同的唯一子列表。 您每次必须创建一个新的子列表。

List<List<T>> parent = new List<List<T>>();
for (counter = 0; counter <= group.Count - 2; counter++)
{
    if (condition)
    {
        var child = new List<T>();
        child.Add(element);
        child.Add(element2);
        parent.Add(child);
    }
}

这可以像这样可视化:

                      child list object
variable              +-----------+
+-------+             |           |
|child  o------------>|           |
+-------+             |           |
                      |           |
                      |           |
                      |           |
                      |           |
                      |           |
                      +-----------+

重新使用该列表的结果将是:

                       child list
                      +-----------+
parent list      +--->|           |
+--------+       |    |-----------|
|        |o----->|    |           |
|--------|       |    |-----------+
|        |o----->|    |           |
|--------|       |    +-----------+
|        |o----->|
|--------|       |
|        |o----->|
|--------|       |
|        |o------+
+--------+

答案 1 :(得分:2)

由于= new List<T>()不是您的选择, 您可以在将其添加到ToList()时在child List上调用parent List

parent.Add(child.ToList());

这将导致将一个新的单独列表添加到parent
然后,清除child List是安全的。

int counter;
List<List<T>> parent= new List<List<T>>();
List<T> child= new List<T>();
for (counter = 0; counter <= group.Count - 2; counter++)
{
    // some code here
    if (//condition)
    {
        child.Add(element);
        child.Add(element2);
        parent.Add(child.ToList());
        child.Clear();
    }
}

答案 2 :(得分:0)

如果你真的想避免分配一个新的列表,那么你必须使用另一种语言。 C# 根本无法执行您要求它执行的操作。

C# 列表是 reference types。当您编写 List<T> x = y; 时,您只需将 x 设为 y 的别名(从技术上讲,您将 y 的引用存储到 x 中)。您不会将 y 引用的实际元素列表复制到 x 中,而只是对任何给定时刻 y 碰巧持有的任何内容的引用。如果您将任何内容更改为 yx 将仅反映这些更改。例如,如果您清除 yx 将引用一个空列表。

如果您想在分配 y 时保留 x 的状态,则必须创建 y 的副本并让 x 引用该副本。

然后你必须决定how deep that copy is

为了让您的列表完全“可重用”(以便您可以对其进行所有可以想象的操作,而不会以任何方式影响 x 引用的列表),您需要一个代价高昂且很可能无用的深拷贝.

如果您只是希望能够随心所欲地添加或删除元素,那么浅拷贝就足够了。

该复制过程,无论是否浅薄,都将涉及在某个时刻创建一个新的 List 实例。这就是引用类型的工作方式。你不能把副本变魔术。因此,如果某些奇怪的规则禁止您创建 List<T> 的新实例,则您的问题没有解决方案。

现在,如果是你无能的老板欺负你采取一些不允许使用“新列表”的“良好做法”,那么扫除地毯下的污垢可能是一种选择,例如:

  • 使用 ToList 偷偷复制列表。

      List<T> PleaseMyCluelessBoss (List<T> myNotToBeAllocatedList)
      {
          return myNotToBeAllocatedList.ToList();
      }
    
  • 在整个列表上使用 GetRange(选择所有元素并将它们复制到新列表中)

      List<T> PleaseMyCluelessBoss (List<T> myNotToBeAllocatedList)
      {
          return myNotToBeAllocatedList.GetRange(0, myNotToBeAllocatedList.Count);
      }
    

还有其他更复杂的方法可以做同样的事情,但是无论您使用什么复杂的解决方法,都会分配一个新列表,然后将原始列表复制到其中,然后您'最终会做与调用 parent.Add(new List<T>(child)) 相同的事情,这可以说是制作列表浅拷贝的最简单方法。啊,但你的要求会得到满足,你的老板会很高兴:看不到“新名单”。

查看您的代码片段,child 列表除了立即填充、复制和清空之外别无其他用途,这基本上是 list initializer 所做的,只是以更有效的方式。如果你问我,明智的做法是取消它:

int counter;
List<List<T>> parent= new List<List<T>>();
// no need to allocate anything there
for (counter = 0; counter <= group.Count - 2; counter++)
{
    // some code here
    if ( /* condition */ )
    {
        // allocate your list on the spot and put it where it belongs
        parent.Add(new List<T> { element, element2 });
    }
}

或者,如果您的“某些代码”碰巧向 child 添加元素,则此版本会将自上次添加以来收集的所有内容转储到 parent 中:

int counter;
List<List<T>> parent= new List<List<T>>();
List<T> child= new List<T>();
for (counter = 0; counter <= group.Count - 2; counter++)
{
    // some code possibly adding elements to child 

    if (/* condition */)
    {
        child.Add(element);
        child.Add(element2);
        parent.Add(child);

        // don't "reuse" the list, just "reuse" the reference to start with a brand new list
        child = new List<T>();
    }
}

当然你有理由不这样做,但是你给出的例子让我一直在猜测为什么你首先要“重用”这个列表......