如何初始化一个List <T>到一个给定的大小(而不是容量)?
.NET提供了一个通用的列表容器,其性能几乎相同(请参阅数组与列表的性能问题)。 然而,它们在初始化方面有很大不同
数组很容易初始化为默认值,根据定义,它们已经具有一定的大小:
string[] Ar = new string[10];
它允许一个安全地分配随机项目,说:
Ar[5]="hello";
与列表的东西更棘手。 我可以看到两种执行相同初始化的方法,这两种方法都不是优雅的:
List<string> L = new List<string>(10); for (int i=0;i<10;i++) L.Add(null);
要么
string[] Ar = new string[10]; List<string> L = new List<string>(Ar);
什么将是一个更干净的方式?
编辑:到目前为止的答案是指能力,这是预填充列表以外的东西。 例如,刚刚创build的容量为10的列表中,不能做L[2]="somevalue"
编辑2:人们想知道为什么我想用这种方式列出,因为它不是它们打算使用的方式。 我可以看到两个原因:
-
人们可以相当有说服力地争辩说,名单是“下一代”arrays,增加了灵活性,几乎没有惩罚。 因此,应该默认使用它们。 我指出他们可能不容易初始化。
-
目前我写的是一个基类,它提供了作为更大框架的一部分的默认function。 在我提供的默认function中,List的大小在高级中是已知的,因此我可以使用一个数组。 不过,我想提供任何基类dynamic扩展它的机会,因此我select一个列表。
我不能说我经常需要这个东西 – 你能提供更多的细节,为什么你想要这个? 我可能把它作为一个辅助类的静态方法:
public static class Lists { public static List<T> RepeatedDefault<T>(int count) { return Repeated(default(T), count); } public static List<T> Repeated<T>(T value, int count) { List<T> ret = new List<T>(count); ret.AddRange(Enumerable.Repeat(value, count)); return ret; } }
您可以使用Enumerable.Repeat(default(T), count).ToList()
但由于缓冲区大小,这将是低效的。
编辑:正如注释中指出的,你可以Repeated
使用循环来填充列表,如果你想。 这也会稍微快一点。 就我个人而言,我发现代码使用Repeat
更具描述性,并怀疑在现实世界中的性能差异将是无关紧要的,但你的里程可能会有所不同。
List<string> L = new List<string> ( new string[10] );
使用以int(“容量”)作为参数的构造函数:
List<string> = new List<string>(10);
编辑:我应该补充说,我同意弗雷德里克。 您使用List的方式与首先使用它背后的全部理由背道而驰。
EDIT2:
编辑2:我目前正在写的是一个基类提供默认function作为一个更大的框架的一部分。 在我提供的默认function中,List的大小在高级中是已知的,因此我可以使用一个数组。 但是,我想给任何基类提供dynamic扩展的机会,因此我select了一个列表。
为什么有人需要知道所有空值的列表的大小? 如果列表中没有真正的值,那么我认为这个长度是0.不pipe怎么说,这是一个错误的事实,这说明它违背了这个类的使用目的。
你为什么要用一个固定值来初始化一个List? 我可以理解,为了性能,你想给它一个初始容量,但是不是常规数组中列表的优点之一,它可以在需要时增长?
当你这样做:
List<int> = new List<int>(100);
您创build一个容量为100个整数的列表。 这意味着您的列表将不需要“增长”,直到您添加第101个项目。 列表的底层数组将被初始化为100。
初始化这样的列表的内容并不真正是列表的内容。 列表被devise来保存对象。 如果要将特定数字映射到特定对象,请考虑使用键值对结构(如哈希表或字典)而不是列表。
如果你想用一些固定值的N个元素来初始化列表:
public List<T> InitList<T>(int count, T initValue) { return Enumerable.Repeat(initValue, count).ToList(); }
你似乎强调需要与你的数据进行位置关联,所以联合数组不会更适合吗?
Dictionary<int, string> foo = new Dictionary<int, string>(); foo[2] = "string";
用你想要的项目数量创build一个数组,然后把数组转换成一个List。
int[] fakeArray = new int[10]; List<int> list = fakeArray.ToList();
这真的取决于你为什么要初始化它。 我不确定用一定数量的空或空元素来初始化它是有用的。 列表的好处是,他们可以根据需要增长。
列表构造函数需要一个容量参数,可以用来初始填充它。
List<string> = new List<string>(10);
string [] temp = new string[] {"1","2","3"}; List<string> temp2 = temp.ToList();
您可以使用Linq巧妙地使用默认值初始化您的列表。 (与David B的答案类似)
var defaultStrings = (new int[10]).Select(x => "my value").ToList();
再往前走一步,用不同的值“string 1”,“string 2”,“string 3”等来初始化每个string:
int x = 1; var numberedStrings = (new int[10]).Select(x => "string " + x++).ToList();
有关IList的通知: MSDN IList备注 :“IList实现分为三类:只读,固定大小和可变大小(…)。有关此接口的通用版本,请参阅System.Collections.Generic.IList<T>
。“
IList<T>
不从IList
inheritance(但是List<T>
确实实现了IList<T>
和IList
),但是总是可变大小的 。 从.NET 4.5开始,我们也有IReadOnlyList<T>
但是AFAIK没有固定大小的generics列表,这就是你正在寻找的。
这是我用于unit testing的样本。 我创build了一个类对象列表。 然后,我用forloop添加了我希望从服务中获得的“X”个对象。 这样,您可以添加/初始化任何给定大小的列表。
public void TestMethod1() { var expected = new List<DotaViewer.Interface.DotaHero>(); for (int i = 0; i < 22; i++)//You add empty initialization here { var temp = new DotaViewer.Interface.DotaHero(); expected.Add(temp); } var nw = new DotaHeroCsvService(); var items = nw.GetHero(); CollectionAssert.AreEqual(expected,items); }
希望我对你们有帮助。
有点晚了,但你提出的第一个解决scheme似乎对我来说要干净得多:你不要分配内存两次。 即使列表constrcutor需要遍历数组,以复制它; 它甚至不知道预先在里面只有空元素。
1. – 分配N-loop N成本:1 *分配(N)+ N * loop_iteration
2. – 分配N – 分配N + loop()成本:2 * allocate(N)+ N * loop_iteration
但List的分配循环可能会更快,因为列表是一个内置的类,但C#是JIT编译sooo …