在c#中设置/扩展List<T>长度

11

在 c# 中,如果给定一个 List<T>,是否有一种方法可以扩展它(在其容量内),并将新元素设置为null?我希望能够像memset一样使用某些方法。我不是在寻找简化的方法,我想要快速的代码。我知道在 C 中,此操作每个条目可能只需要1-3个汇编操作。

我找到的最佳解决方案是这个

list.AddRange(Enumerable.Repeat(null, count-list.Count));

然而,那是使用 C# 3.0(<3.0 更优),可能会生成并评估枚举器。

我的当前代码使用:

while(list.Count < lim) list.Add(null);

那么这就是时间成本的起点。

这个问题背后的动机是,我需要设置第n个元素,即使它在旧Count之后。


如果这种情况经常发生,我建议使用Dictionary<int,T>而不是List<T>。 - configurator
3个回答

12

最简单的方法可能是创建一个临时数组:

list.AddRange(new T[size - count]);

在这里,size是所需的新大小,count是列表中项目的计数。然而,对于相对较大的size - count值,这可能会导致性能下降,因为它可能会导致列表多次重新分配。(*)此外,它还具有分配额外临时数组的缺点,这取决于您的要求,可能不可接受。您可以通过使用以下方法来缓解这两个问题,但需要更明确的代码:

public static class CollectionsUtil
{
    public static List<T> EnsureSize<T>(this List<T> list, int size)
    {
        return EnsureSize(list, size, default(T));
    }

    public static List<T> EnsureSize<T>(this List<T> list, int size, T value)
    {
        if (list == null) throw new ArgumentNullException("list");
        if (size < 0) throw new ArgumentOutOfRangeException("size");

        int count = list.Count;
        if (count < size)
        {
            int capacity = list.Capacity;
            if (capacity < size)
                list.Capacity = Math.Max(size, capacity * 2);

            while (count < size)
            {
                list.Add(value);
                ++count;
            }
        }

        return list;
    }
}

这里唯一使用到C# 3.0的是使用"this"修饰符将它们变成扩展方法。去掉修饰符后,在C# 2.0中也可以使用。
不幸的是,我从未比较过这两个版本的性能,所以不知道哪个更好。
哦,你知道你可以通过调用Array.Resize<T>来调整数组大小吗?我之前并不知道。:) 更新:
(*) 使用list.AddRange(array)不会导致枚举器被使用。通过进一步查看Reflector,发现数组将被转换为ICollection<T>,并使用Count属性,以便只进行一次分配。

“ list.AddRange(new T[size - count]);” 在注释中看起来不错。不知道优化器是否可以避免枚举器。 - BCS
@BCS,我错了,List<T>.AddRange 的实现实际上对这种情况进行了优化。我已经更新了我的帖子。 - Hosam Aly

3
static IEnumerable<T> GetValues<T>(T value, int count) {
   for (int i = 0; i < count; ++i)
      yield return value;
}

list.AddRange(GetValues<object>(null, number_of_nulls_to_add));

这将适用于2.0以上版本


这样做的好处是它可以填充列表所需的值。但是,如果只需要空值或零值,则仅使用list.AddRange(new T[count - list.Count]即可。 (我猜对于小数组大小来说,它的性能会更好。) - Hosam Aly

-3

你为什么想要这样做呢? List 的主要优势在于它可以根据需要增长,那么你为什么要向其中添加一些 null 或默认元素呢?

在这种情况下,使用数组不是更好吗?


如果我没记错的话,数组是不能增长的(你可以创建一个更大的副本,但不能增长它)。 - BCS
2
List<T> 不是一个数组。它可以增长。 - Joel Coehoorn
实际上,数组是可以增长的,但如果您想将其设置为空元素数量,使用列表有什么用呢? 或者,我只是误解了问题吗? - Frederik Gheysels
1
实际上数组是可以增长的!我之前不知道,但我刚刚注意到了Array.Resize()方法:http://msdn.microsoft.com/en-us/library/bb348051.aspx - Hosam Aly
5
Array.Resize() 不会改变数组的大小,它会创建一个新的数组并复制元素。 - Lou Franco
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接