所以,这是我的问题,我有一个给定的对象,它是一个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.
提前致谢!
答案 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++;
}
}
}