如何初始化一个列表到一个给定的大小(而不是容量)?
.NET提供了一个通用列表容器,其性能几乎相同(请参阅数组与列表性能问题)。然而,它们在初始化方面有很大不同如何初始化一个列表<T>到一个给定的大小(而不是容量)?
数组是很容易用默认值进行初始化,并定义他们已经有一定的规模:
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);
这将是一个更清洁的方式?
编辑:到目前为止的答案是指能力,这是比预填充列表别的东西。例如,在刚创建的容量为10的列表上,人们不能这样做L[2]="somevalue"
编辑2:人们想知道为什么我想以这种方式使用列表,因为它不是它们打算使用的方式。我可以看到两个方面的原因:
人们可以令人信服地认为,名单是“下一代”阵列,增加了灵活性,几乎没有损失。因此,应该默认使用它们。我指出他们可能不容易初始化。
我现在写的是一个基类,它提供了作为更大框架一部分的默认功能。在我提供的默认功能中,List的大小在高级中是已知的,因此我可以使用一个数组。但是,我想为任何基类提供动态扩展的机会,因此我选择了一个列表。
我不能说我经常需要这个 - 你能给出更多的细节,为什么你想要这个?我可能会把它作为一个静态方法的辅助类:
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
的代码更具描述性,并且怀疑在现实世界中,性能差异将无关紧要,但是您的里程可能会有所不同。
使用这需要一个int( “能力”)作为参数的构造:
List<string> = new List<string>(10);
编辑:我要补充一点,我弗雷德里克同意。您使用List的方式与首先使用它的背后的全部理由背道而驰。
EDIT2:
编辑2:什么我目前正在写一个基类产品默认的功能更大的框架的一部分。在我提供的默认功能中,List的大小在高级中是已知的,因此我可以使用一个数组。但是,我想为任何基类提供动态扩展的机会,因此我选择了一个列表。
为什么任何人需要知道所有空值的列表大小?如果列表中没有真正的值,我会预期这个长度为0.总而言之,这是一个错误,这表明它违背了该类的预期用途。
为什么你要使用列表,如果你想用固定值初始化它? 我可以理解 - 为了性能 - 你想给它一个初始容量,但是不是常规数组上的列表的优点之一,它可以在需要时增长?
当你这样做:
List<int> = new List<int>(100);
创建,其容量为100个整数的列表。这意味着你的列表不需要“增长”,直到你添加第101项。 列表的底层数组将被初始化为100的长度。
初始化列表中的内容实际上不是列表的内容。列表旨在保存对象。如果要将特定数字映射到特定对象,请考虑使用键值对结构,如散列表或字典而不是列表。
这真的取决于你为什么要初始化它。我不确定用一定数量的空或空元素初始化它是有用的。列表的优点是,它们可以根据需要增长。
列表构造函数需要一个容量参数,它可以用来初始填充它。
List<string> = new List<string>(10);
string [] temp = new string[] {"1","2","3"};
List<string> temp2 = temp.ToList();
如果你想初始化一些固定值的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";
List<string> L = new List<string> (new string[10]);
你可以使用LINQ到一个默认值初始化巧妙您的列表。 (到David B's answer类似。)
var defaultStrings = (new int[10]).Select(x => "my value").ToList();
转到一个步骤更远并初始化每个字符串与不同的值 “串1”, “字符串2”, “字符串3”,等:
int x = 1;
var numberedStrings = (new int[10]).Select(x => "string " + x++).ToList();
创建数组,其中包含您想要的项目数量,然后将数组转换为List。
int[] fakeArray = new int[10];
List<int> list = fakeArray.ToList();
约IList中通知: MSDN IList Remarks: “的IList实现分为三类:。只读,固定大小的,并大小可变的(...)对于该接口的通用版本,见 System.Collections.Generic.IList<T>
。“
IList<T>
不继承IList
(但不List<T>
同时实现IList<T>
和IList
),但始终是variable-size。 自.NET 4.5以来,我们也有IReadOnlyList<T>
但AFAIK,没有固定大小的通用列表,这将是你在找什么。
这是我用我的单元测试的样本。我创建了一个类对象列表。然后,我使用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);
}
希望我对你们有所帮助。
你提出
有点晚了,但第一个解决方案似乎更干净对我说:你不分配内存的两倍。甚至列表constrcutor需要通过数组循环以复制数组;它甚至不知道预先在里面只有空元素。
1. - 分配Ñ - 循环N 成本:1 *分配(N)+ N * loop_iteration
2. - 分配Ñ - 分配N +环() 成本:2 *分配(N)+ N * loop_iteration
但是名单的分配,因为名单是一个循环可能会更快内置类,但C#是JIT编译SOOO ...
“编辑:答案至今指容量,这是除了预填充之外的其他内容名单。举例来说,只是一个容量10创建的列表上,一个人不能做L [2] =“someValue中”” 鉴于此修改,也许你应该改写的问题标题...... – aranasaurus 2009-01-21 21:03:36
可是,有什么用预-populating空值的列表,导致这就是该topicstarter试图做 – 2009-01-21 21:04:48
弗雷德里克:?什么时候会变成这样......需要不断 – 2009-01-21 21:05:29