如何在 C# 中构建结构列表数组(具有预定义的数组大小)
Posted
技术标签:
【中文标题】如何在 C# 中构建结构列表数组(具有预定义的数组大小)【英文标题】:How to build Array of Lists of Structs in C# (with predefined size of the Array) 【发布时间】:2020-01-23 21:36:45 【问题描述】:尝试在 C# 中构建结构列表数组。并通过最佳尝试获得 System.NullReferenceException(test[i].Add(info1);
行错误)
问题根本不是如何避免System.NullReferenceException,而更像是如何快速构建具有预定义数组大小的列表数组,从而能够使用@ 987654323@ 在里面。如果可能不循环整个数组,只需创建列表。
所以这些是要求:
数组的大小应该是预定义的; 每个节点的列表数量应该是任意的,并且应该有可能很容易添加这些列表; 结构应包含struct Info
。
这是我到目前为止管理的代码(复制和粘贴应该可以复制错误):
using System.Collections.Generic;
class Startup
static void Main()
int entry = 1233;
List<Info>[] test = new List<Info>[entry];
for (int i = 0; i < 500 ; i+=3)
Info info1 = new Info()
capacity = i * 2,
name = i.ToString()
;
test[i].Add(info1);
for (int i = 0; i < 1000; i+=5)
Info info2 = new Info();
info2.capacity = i * 2;
info2.name = i.ToString() + i.ToString();
test[i].Add(info2);
struct Info
public int capacity;
public string name;
【问题讨论】:
您只初始化了整个数组,而不是其中的列表。 What is a NullReferenceException, and how do I fix it?的可能重复 @BrootsWaymb - 有没有比在循环前添加for (int i = 0; i < test.Length; i++) test[i] = new List<Info>();
更快的方法?
test[i] = new List数组的每个元素都没有定义为对象是List
你应该这样做:
using System.Collections.Generic;
class Startup
static void Main()
int entry = 1233;
List<Info>[] test = new List<Info>[entry];
for (int i = 0; i < 500 ; i+=3)
Info info1 = new Info()
capacity = i * 2,
name = i.ToString()
;
// if null initialise the list
if(test[i] == null) test[i] = new List<Info>();
test[i].Add(info1);
for (int i = 0; i < 1000; i+=5)
Info info2 = new Info();
info2.capacity = i * 2;
info2.name = i.ToString() + i.ToString();
// if null initialise the list
if(test[i] == null) test[i] = new List<Info>();
test[i].Add(info2);
struct Info
public int capacity;
public string name;
【讨论】:
或者在第一个循环中完全跳过 if 检查。永远都是真的。 @CodeStranger 是的,把它放在那里,以防他移动东西。如果是我,我会选择List<Info>[] test = Enumerable.Range(0,entry ).Select(o=>new List<Info>()).ToArray();
并收工
@Franck - Idk,1 班轮似乎有很多“糖”。一般来说,我想这就像一个标准的性能循环。我正在与那些使用 C++ 和“花哨”向量的人“竞争”,这些人在速度方面具有一般魔力。 (不过 1 班轮很好)
@Vityata 它所做的只是初始化数组的所有元素。你不会有一个空值。如果您要迭代所有元素并最终初始化 100% 的数组,那么这一行会更快。编译器似乎喜欢连续多次询问相同的操作,而不是在需要时。同样,最好初始化数组中的所有项目。【参考方案2】:
试试这个:
using System.Collections.Generic;
class Startup
static void Main()
int entry = 1233;
List<Info>[] test = new List<Info>[entry];
for (int i = 0; i < 500 ; i+=3)
Info info1 = new Info()
capacity = i * 2,
name = i.ToString()
;
test[i] = new List<Info> info1;
for (int i = 0; i < 1000; i += 5)
Info info2 = new Info();
info2.capacity = i * 2;
info2.name = i.ToString() + i.ToString();
if (test[i] == null)
test[i] = new List<Info> info2 ;
else
test[i].Add(info2);
struct Info
public int capacity;
public string name;
【讨论】:
这会将循环 2 中的新列表分配给循环 1 中已经有列表的位置。第一次命中索引时,这是一种不错的单行方法,否则您将丢失信息(在位置15 例如,就像@Vityata 提到的那样)。 在每次之前添加检查有点过分“补丁”,我可能会使用 1-linerfor (int i = 0; i < test.Length; i++) test[i] = new List<Info>();
@Vityata 你可以这样做,但是添加一个空检查比为所有列表分配内存要便宜得多(对于不能被 3 和 5 整除的数字)。但是,如果您打算稍后使用这些列表,那么这似乎是更明智的方法。
@ui_guy - null 检查很快,是的,但是忘记一个的“代价”似乎相当高。我希望有一些“动态”、“快速”和“干净”的东西。但我在这里妥协的一件事是“快速”。【参考方案3】:
试试这个:
using System.Collections.Generic;
class Startup
static void Main()
int entry = 1233;
var test = Enumerable.Range(0,entry)
.Select(i=>
var y = new List<Info>();
if(i%3==0 && i < 500)
y.Add(new Info
capacity = i*2,
name = i.ToString()
);
if(i%5==0 && i < 1000)
y.Add(new Info
capacity = i*2,
name = i.ToString() + i.ToString()
);
return y;
).ToArray();
struct Info
public int capacity;
public string name;
【讨论】:
感谢您的输入,在一般情况下它更快(只要它跳过无意义的循环)。两个循环的想法是表明,数据必须能够独立输入,因此代码的一部分应该保持原样(例如,2个单独的循环)。 在这种情况下,我只需用var test = Enumerable.Range(0,entry).Select(i=>new List<Info>()).ToArray();
初始化所有元素
到目前为止,这似乎是一个不错的选择。 @Franck 在他/她的评论中提出了同样的建议。
我上面发布的代码的好处是可以很容易地转化为懒惰。只需删除.ToArray()
,并将其引用为IEnumerable<List<Info>>
,它会在您使用它时进行计算。如果你不消耗整个东西,那么你就不需要计算整个数组。
好吧,如果性能绝对是重中之重,那么我建议以老式的方式创建它... var test = List<Info>[entry]; for(var i=0;i<entry;i++) test[i]=new List<Info>();
代替。不过,性能差异应该很小。以上是关于如何在 C# 中构建结构列表数组(具有预定义的数组大小)的主要内容,如果未能解决你的问题,请参考以下文章