C#Enumerable.Take默认值

Hec*_*tor 19 .net c# linq ienumerable take

从C#中的Enumerable中获取精确x值的最佳方法是什么?如果我像这样使用Enumerable .Take():

var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
Run Code Online (Sandbox Code Playgroud)

结果只有10个元素.

我想用默认值填充缺少的条目.像这样的东西:

var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int));  //Is there anything like this?
Run Code Online (Sandbox Code Playgroud)

在C#中是否有这样的功能,如果没有,那么实现这一目标的最佳方法是什么?

Mat*_*and 17

你可以这样做:

var result = myList.Concat(Enumerable.Repeat(default(int), 20)).Take(20); 
Run Code Online (Sandbox Code Playgroud)

并且很容易将其转换为扩展方法:

public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int count, T defaultValue)
{
    return  list.Concat(Enumerable.Repeat(defaultValue, count)).Take(count);
}
Run Code Online (Sandbox Code Playgroud)

这里有一个微妙的问题.这对于值类型非常适用,对于引用类型,如果defaultValue不是null,则多次添加相同的对象.这可能不是你想要的.例如,如果你有这个:

var result = myList.TakeOrDefault(20, new Foo());
Run Code Online (Sandbox Code Playgroud)

您将添加相同的实例Foo来填充您的集合.要解决这个问题,你需要这样的东西:

public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int count, Func<T> defaultFactory)
{
    return  list.Concat(Enumerable.Range(0, count).Select(i => defaultFactory())).Take(count);
}
Run Code Online (Sandbox Code Playgroud)

您可以这样称呼:

var result = myList.TakeOrDefault(20, () => new Foo())
Run Code Online (Sandbox Code Playgroud)

当然,这两种方法可以共存,因此您可以轻松地:

// pad a list of ints with zeroes
var intResult = myIntList.TakeOrDefault(20, default(int));
// pad a list of objects with null
var objNullResult = myObjList.TakeOrDefault(20, (object)null);
// pad a list of Foo with new (separate) instances of Foo
var objPadNewResult = myFooList.TakeOrDefault(20, () => new Foo());
Run Code Online (Sandbox Code Playgroud)


Jam*_*iec 11

它默认不存在,但是作为扩展方法编写起来很容易

public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> items, int count, T defaultValue)
{
    var i = 0;
    foreach(var item in items)
    {
        i++;
        yield return item;
        if(i == count)
             yield break;
    }
    while(i++<count)
    {
        yield return defaultValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

实例:http://rextester.com/XANF91263

  • @YuvalItzchakov如果他们想提供他们自己的默认值,则有用,但中间的会议可以作为可选参数. (2认同)

dca*_*tro 5

您正在寻找的是一种通用PadTo方法,如果需要,可以使用给定值扩展集合的长度.

public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len)
{
    return source.PadTo(len, default(T));
}

public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len, T elem)
{
    return source.PadTo(len, () => elem);
}

public static IEnumerable<T> PadTo<T>(this IEnumerable<T> source, int len, Func<T> elem)
{
    int i = 0;
    foreach(var t in source)
    {
        i++;
        yield return t;
    }

    while(i++ < len)
        yield return elem();
}
Run Code Online (Sandbox Code Playgroud)

你现在可以表达:

myList.Take(20).PadTo(20);
Run Code Online (Sandbox Code Playgroud)

这类似于Scala的 List[A].padTo