【问题标题】:C# Adding and Removing elements to an array with an existing sizeC# 向具有现有大小的数组添加和删除元素
【发布时间】:2018-05-18 15:07:36
【问题描述】:

我只是有一个问题。我注意到,与 C++ 不同,C# 在数组方面有点复杂。我一直在寻找的数组中的一个特性或技术是:我想以一种更高效、更简单的方式添加元素或从中删除元素。

例如,我有一个名为“食物”的数组。

string[] food = {'Bacon', 'Cheese', 'Patty', 'Crabs'}

然后我决定添加更多食物。正如我所见,C# 的问题是除非您使用 ArrayList,否则这是不可能的。数组本身怎么样?我想将数组用作某种我添加东西的库存。

非常感谢!

【问题讨论】:

  • 听起来你想要一个 List,而不是一个数组。数组是固定大小的。
  • 是什么让你不想使用List<T>
  • 在 C++ 中,您也不能轻松地在数组中添加或删除项目。你也应该在那里使用std::vector(相当于C#List

标签: c# arrays


【解决方案1】:

在不分配新数组的情况下,您无法在 C# 中使用数组来做到这一点。因为数组的大小是固定的。

如果您希望能够从容器中添加/删除元素,您可以使用List<T>。或者,您可以使用 ArrayList,但不建议这样做,因为在大多数情况下,List<T> 具有性能优势。

在内部都使用数组作为数据的默认容器。他们还会根据您放入或取出的数据量来调整容器的大小。

在您的示例中,您将使用类似的列表

 List<string> food = new List<string> { "Bacon", "Cheese", "Patty", "Crabs" };

 food.Add("Milk"); //Will add Milk to the list
 food.Remove("Bacon"); //Will remove "Bacon"

MSDN 上的列表:Docs

【讨论】:

  • 我没有投反对票,我认为你的答案不值得投反对票,但可能会添加一些使用 List&lt;T&gt; 的示例,真的“加强”你的答案
  • 它没有回答问题,您也没有提供示例。但我尊重反对票,因为现在是星期五 :-)
  • 感谢反馈,我修改了答案。
  • 我会从您的答案中删除ArrayList,因为它并不是一个很好的集合类型。只要坚持List&lt;T&gt;。另外值得一提的是List&lt;T&gt; 在内部如何使用数组,但它会为您处理所有工作,而无需您自己管理
  • @maccettura 感谢您的反馈,我认为应该提及它,因为它是一个实际可行的解决方案。但也许只是不鼓励使用它。
【解决方案2】:

要真正回答这个问题,您只需要调整数组的大小。 Array.Resize(ref 数组, ); 是数组的新长度

【讨论】:

  • 这会分配一个新数组。
  • 是的..这是一个数组,您必须创建一个新数组...我猜他可以使用 List 然后将其推送到数组中。
  • List&lt;&gt; 在内部也只使用一个数组,每当空间不足时,它也必须重建数组(即分配新数组并从前一个数组复制元素)......所以通过使用List&lt;&gt; 你无法摆脱分配,你不必自己做。
  • 显然是的,StringBuilder 或任何“可扩展/收缩”大小的东西也是如此。
【解决方案3】:

要在不调整大小的情况下真正将元素添加到现有数组中,你做不到。或者,你可以吗?是的,但有一些诡计,在某些时候你可能会说不值得。

考虑分配一个您预计可能大小的数组。显然,您必须很好地估计以避免大量未使用的空间。数组中的空槽将由sentinel value 标记;对于string,显而易见的候选人是null。通过跟踪哨兵的第一个索引,您将知道数组的“真实”大小。这表明ArrayWrapper 类将封装数组和“真实大小”。

该包装器可以添加 Add()AddRange() 将标记值替换为真实值而不进行分配。

说了这么多,缺点是你必须分配一个新数组。除非您有非常具体的要求可以减少分配,否则使用包装器手动执行此操作是没有意义的。

因此,对于最常见的情况,请坚持使用 List&lt;&gt;,它会为您做到这一点。使用该列表,您可以通过调用带有初始容量参数的构造函数来构造它。添加将使用底层数组而不重新分配,直到达到限制。

在某种程度上List&lt;&gt; 您的包装器使用分配模型,原始作者决定在大多数情况下最小化分配。这可能比你写的任何东西都表现得更好除非你真的可以利用你的域

【讨论】:

    【解决方案4】:

    理想情况下,如果您要拥有一个可变大小的字符串数组,List 会更好。您所要做的就是调用list.Add("")list.Remove("") 和其他等效方法。

    但是如果你想继续使用字符串数组,你可以创建一个函数或类来接受一个数组,创建一个更大或更小的新数组,用原来的值重新填充该数组数组,并返回新数组。

    public string[] AddFood(string[] input, string var)
    {
        string[] result = new string[input.Length + 1];
        for (int i = 0; i < input.Length; i++)
        {
            result[i] = input[i];
        }
        result[result.Length - 1] = var;
        return result;
    }
    
    public string[] RemoveFood(string[] input, int index)
    {
        string[] result = new string[input.Length - 1];
        for (int i = 0; i < input.Length; i++)
        {
            if (i < index) {
                result[i] = input[i];
            }
            else
            {
                result[i] = input[i + 1];
            }
        }
        return result;
    }
    

    再次,我强烈建议您改用 List 方法。这些列表的唯一缺点是它会将它们附加到末尾,而不是确定您想要放置所述项目的位置。

    List<string> myFoods = new List<String>(food);
    myFoods.Add("Apple");
    myFoods.Remove("Bacon");
    myFoods.AddRange(new string[] { "Peach", "Pineapple" });
    myFoods.RemoveAt(2);
    Console.WriteLine(myFoods[0]);
    

    如果你想要一个更像数组的列表,还有 ArrayList,但它是older code and unfavoured

    ArrayList myFoods = new ArrayList(food);
    myFoods.Add("Apple");
    myFoods.Remove("Bacon");
    myFoods.AddRange(new string[] { "Peach", "Pineapple" });
    myFoods.RemoveAt(2);
    Console.WriteLine(myFoods[0]);
    

    我希望这会有所帮助。

    【讨论】:

    • 感谢您向我解释这一点。虽然我没有给你最好的答案,但我非常感谢你给出的所有解释,所以我可以理解它。
    • 这就是目的:)
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 2013-12-20
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    相关资源
    最近更新 更多