如何使用扩展方法使集合成为“n”元素?

时间:2012-12-13 23:07:01

标签: c# linq extension-methods

所以,这是我的问题,我有一个给定的对象,它是一个IEnumerable,我保证所说的集合总是最多有4个元素。现在,由于一个不重要的原因,我希望能够以一种优雅的方式“强制”该集合包含4个元素,如果它没有那么多。

我已经完成了一些研究,而且最令人信服的候选人是Zip,但它会在收到最短的收集结束后停止压缩。

有没有办法在不制作我自己的扩展方法的情况下这样做? 为了更好地解释自己:

var list1 = new List<Dog> {
    new Dog { Name = "Puppy" }
}
var list2 = new List<Dog> {
    new Dog { Name = "Puppy1" },
    new Dog { Name = "Puppy2" },
    new Dog { Name = "Puppy3" },
    new Dog { Name = "Puppy4" },
}

var other1 = list1.ExtendToNElements(4).ToList();
//Now other1's first element is an instance of Dog with Name = "Puppy"
//And the following 3 elements are null, or have a Dog with no name
//I don't really care about that

var other2 = list2.ExtendToNElements(4).ToList();
//other2 is the same as list2, nothing got added.

提前致谢!

3 个答案:

答案 0 :(得分:4)

快速单行(应该算作“没有扩展方法可行”):

public static IEnumerable<TItem> Extend<TItem>(
            this IEnumerable<TItem> source, 
            int n)
{
    return source.Concat(Enumerable.Repeat(default(TItem), n))
                 .Take(n);
}

由于Repeat采用显式计数,因此传入n会给出合理的上限。无论如何,元素都是按需生成的。使用source.Count()会强制执行source,这是不理想的。

稍微过度设计和灵活的版本:

public static IEnumerable<TItem> Extend<TItem>(
            this IEnumerable<TItem> source, 
            int n, 
            Func<TItem> with) 
{
    return source.Concat(
        from i in Enumerable.Range(0, n) select with()
    ).Take(n);
}

public static IEnumerable<TItem> Extend<TItem>(
            this IEnumerable<TItem> source, 
            int n, 
            TItem with = default(TItem)) 
{
    return source.Extend(n, with: () => with);
}

答案 1 :(得分:3)

您可以使用MoreLinq的Pad方法:http://code.google.com/p/morelinq/(NuGet:http://www.nuget.org/packages/morelinq

这将附加类型的默认值(在这种情况下为null):

var other1 = list1.Pad(4).ToList();

或者,如果您想提供默认值:

var other1 = list1.Pad(4, "Puppy_null").ToList();

或者如果你想要那些编号的小狗:

var other1 = list.Pad(4, (count) => "Puppy" + count).ToList();

Pad方法如果长度已经等于或大于您的打击垫尺寸,则不会添加其他条目。

以下是Pad实施,特别是如果您想在不引入整个项目的情况下合并/改编它:http://code.google.com/p/morelinq/source/browse/MoreLinq/Pad.cs

答案 2 :(得分:0)

    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.Capacity = 4;
            var items = list.TakeOrDefault(4);


        }
    }

    public static class EnumerableExtensions
    {
        public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> enumerable, int length)
        {
            int count = 0;
            foreach (T element in enumerable)
            {
                if (count == length)
                    yield break;

                yield return element;
                count++;
            }
            while (count != length)
            {
                yield return default(T);
                count++;
            }
        }
    }