C#可枚举。使用默认值获取

C#可枚举。使用默认值获取,c#,.net,linq,ienumerable,take,C#,.net,Linq,Ienumerable,Take,从C#中的可枚举项中精确获取x值的最佳方法是什么。 如果我像这样使用Enumerable.Take(): var myList = Enumerable.Range(0,10); var result = myList.Take(20); var myList = Enumerable.Range(0,10); var result = myList.TakeOrDefault(20, default(int)); //Is there anything like this? public

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

var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int));  //Is there anything like this?
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);
}
var result = myList.TakeOrDefault(20, () => new Foo())
结果将只有10个元素

我想用默认值填充缺少的条目。 大概是这样的:

var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int));  //Is there anything like this?
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);
}
var result = myList.TakeOrDefault(20, () => new Foo())

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

为此,您可以使用
Concat
。您可以使用一个简单的帮助器方法将这一切连接在一起:

public IEnumerable<T> TakeSpawn(this IEnumerable<T> @this, int take, T defaultElement)
{
  return @this.Concat(Enumerable.Repeat(defaultElement, take)).Take(take);
}
public IEnumerable TakeSpawn(this IEnumerable@this,int take,T defaultElement)
{
返回@this.Concat(Enumerable.Repeat(defaultElement,take)).take(take);
}

其思想是,您总是在原始枚举的末尾附加另一个枚举,因此,如果输入没有足够的元素,它将从
Repeat
开始枚举,默认情况下它不在那里,但作为扩展方法编写非常简单

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;
    }
}
公共静态IEnumerable TakeOrderFault(此IEnumerable项,int计数,T默认值)
{
var i=0;
foreach(项目中的var项目)
{
i++;
收益回报项目;
如果(i==计数)
屈服断裂;
}

而(i++您可以执行以下操作:

var result = myList.Concat(Enumerable.Repeat(default(int), 20)).Take(20); 
很容易将其转化为一种扩展方法:

public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int count, T defaultValue)
{
    return  list.Concat(Enumerable.Repeat(defaultValue, count)).Take(count);
}
您将添加相同的
Foo
实例来填充集合。要解决此问题,您需要以下内容:

var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int));  //Is there anything like this?
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);
}
var result = myList.TakeOrDefault(20, () => new Foo())
当然,这两种方法可以共存,因此您可以轻松获得:

// 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());

据我所知,.NET Framework中没有任何内容。不过,使用扩展方法可以轻松实现这一点,如果您自己提供默认值,它适用于所有类型:

public static class ListExtensions
{
    public static IEnumerable<T> TakeOrDefault<T>(this List<T> list, int count, T defaultValue)
    {
        int missingItems = count - list.Count;
        List<T> extra = new List<T>(missingItems);

        for (int i = 0; i < missingItems; i++)
            extra.Add(defaultValue);

        return list.Take(count).Concat(extra);
    }
}
公共静态类ListExtensions
{
公共静态IEnumerable TakeOrderFault(此列表,int count,T defaultValue)
{
int missingItems=count-list.count;
额外列表=新列表(缺失项);
for(int i=0;i
您正在寻找的是一种通用的
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();
}

这类似于Scala的

为什么不编写一个扩展方法来检查计数并返回剩余条目的默认值:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> values = new List<int>{1, 2, 3, 4};

            IEnumerable<int> moreValues = values.TakeOrDefault(3, 100);
            Console.WriteLine(moreValues.Count());

            moreValues = values.TakeOrDefault(4, 100);
            Console.WriteLine(moreValues.Count());

            moreValues = values.TakeOrDefault(10, 100);
            Console.WriteLine(moreValues.Count());

        }
    }

    public static class ExtensionMethods
    {
        public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> enumerable, int count, T defaultValue)
        {
            int returnedCount = 0;
            foreach (T variable in enumerable)
            {
                returnedCount++;
                yield return variable;
                if (returnedCount == count)
                {
                    yield break;
                }
            }

            if (returnedCount < count)
            {
                for (int i = returnedCount; i < count; i++)
                {
                    yield return defaultValue;
                }
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间控制台应用程序3
{
班级计划
{
静态void Main(字符串[]参数)
{
列表值=新列表{1,2,3,4};
IEnumerable moreValues=values.takeOrderFault(3100);
WriteLine(moreValues.Count());
moreValues=values.takeOrderFault(4100);
WriteLine(moreValues.Count());
moreValues=values.takeOrderFault(10100);
WriteLine(moreValues.Count());
}
}
公共静态类扩展方法
{
公共静态IEnumerable TakeOrderFault(此IEnumerable enumerable,int count,T defaultValue)
{
int returnedCount=0;
foreach(可枚举中的T变量)
{
returnedCount++;
收益率变量;
如果(returnedCount==计数)
{
屈服断裂;
}
}
如果(返回计数<计数)
{
for(int i=returnedCount;i
我为此编写了一个快速扩展,它依赖于T是值类型

  public static class Extensions
    {
        public static IEnumerable<T> TakeOrDefault<T>(this IEnumerable<T> list, int totalElements)
        {
            List<T> finalList = list.ToList();

            if (list.Count() < totalElements)
            {
                for (int i = list.Count(); i < totalElements; i++)
                {
                    finalList.Add(Activator.CreateInstance<T>());
                }
            }

            return finalList;
        }
    }
公共静态类扩展
{
公共静态IEnumerable TakeOrderFault(此IEnumerable列表,int totalElements)
{
List finalList=List.ToList();
if(list.Count()
没有真正的点减去计数(如果你只是想跟随
Take
,这可能会更简洁。)我喜欢你的第二个解决方案。我会放弃第一个解决方案-它可能会引发异常(如你所说)它枚举了两次myList
。感谢Concat/Repeat版本完美地满足了我的需要。为什么不编写一个扩展方法来检查计数并返回剩余条目的默认值呢?@Jamiec如果其他人已经回答了,回答是错的吗?我说可以通过扩展方法和sat d来完成own来框定答案。这花了我很多时间,但如果我写了,我会发帖的something@GaneshR.-不,一点也不。但是你可能想回来删除你的评论,否则看起来有点不对劲weird@MattiVirkkunen从技术上来说,是的。但是从语义上来说,它是非常不同的。当然,对于没有简单l的类型,它更有用iterals,如
default(string)
default(DateTime)
。同样重要的是,您可以将
default(T)
与泛型一起使用。@MattiVirkkunen您和我不同意什么比-
DateTime更具可读性。MinValue
对我来说有一个明确的含义,即“这是DateTime可能具有的最低值”.
default(DateTime)
表示“这是默认值”。
null
字符串没有字符串文字。Empty
是空字符串(是否使用
string.Empty
@”
?)。
默认(字符串)
是一个
null
类型的
string
——对于类型推断非常重要。最初设计的功能并不重要——重要的是它实际上是什么