C# Enumerable.Take 具有默认值
C# Enumerable.Take with default value
在 C# 中从 Enumerable 中准确获取 x 值的最佳方法是什么。
如果我像这样使用 Enumerable .Take() :
var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
结果将只有 10 个元素。
我想用默认值填充缺失的条目。
像这样:
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int)); //Is there anything like this?
C# 中是否有这样的功能?如果没有,实现此功能的最佳方法是什么?
您可以使用 Concat
来达到这个目的。您可以使用一个简单的辅助方法将它们连接在一起:
public IEnumerable<T> TakeSpawn(this IEnumerable<T> @this, int take, T defaultElement)
{
return @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;
}
}
你可以这样做:
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);
}
但是这里有一个微妙的陷阱。 对于值类型,对于引用类型,如果您的 defaultValue
不为空,那么您将添加 相同的 object ]多次。这可能不是你想要的。例如,如果你有这个:
var result = myList.TakeOrDefault(20, new Foo());
您将添加 Foo
的相同实例来填充您的 collection。要解决该问题,您需要这样的东西:
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())
当然,两种方法都可以co-exist,所以你可以轻松拥有:
// 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);
}
}
您正在寻找的是一种通用的 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();
}
您现在可以表达:
myList.Take(20).PadTo(20);
这类似于 Scala 的 List[A].padTo
为什么不写一个扩展方法来检查计数和returns剩余条目的默认值:
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;
}
}
}
}
}
我为此写了一个快速扩展,它依赖于 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;
}
}
在 C# 中从 Enumerable 中准确获取 x 值的最佳方法是什么。 如果我像这样使用 Enumerable .Take() :
var myList = Enumerable.Range(0,10);
var result = myList.Take(20);
结果将只有 10 个元素。
我想用默认值填充缺失的条目。 像这样:
var myList = Enumerable.Range(0,10);
var result = myList.TakeOrDefault(20, default(int)); //Is there anything like this?
C# 中是否有这样的功能?如果没有,实现此功能的最佳方法是什么?
您可以使用 Concat
来达到这个目的。您可以使用一个简单的辅助方法将它们连接在一起:
public IEnumerable<T> TakeSpawn(this IEnumerable<T> @this, int take, T defaultElement)
{
return @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;
}
}
你可以这样做:
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);
}
但是这里有一个微妙的陷阱。 对于值类型,对于引用类型,如果您的 defaultValue
不为空,那么您将添加 相同的 object ]多次。这可能不是你想要的。例如,如果你有这个:
var result = myList.TakeOrDefault(20, new Foo());
您将添加 Foo
的相同实例来填充您的 collection。要解决该问题,您需要这样的东西:
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())
当然,两种方法都可以co-exist,所以你可以轻松拥有:
// 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);
}
}
您正在寻找的是一种通用的 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();
}
您现在可以表达:
myList.Take(20).PadTo(20);
这类似于 Scala 的 List[A].padTo
为什么不写一个扩展方法来检查计数和returns剩余条目的默认值:
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;
}
}
}
}
}
我为此写了一个快速扩展,它依赖于 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;
}
}