使用扩展方法,我们可以编写方便的LINQ操作符来解决通用问题。
我想听听您在System.Linq
命名空间中缺少哪些方法或重载以及您如何实现它们。
干净而优雅的实现,最好使用现有的方法。
使用扩展方法,我们可以编写方便的LINQ操作符来解决通用问题。
我想听听您在System.Linq
命名空间中缺少哪些方法或重载以及您如何实现它们。
干净而优雅的实现,最好使用现有的方法。
(自本回答撰写以来,这些已被添加到.NET中。)
/// <summary>Adds a single element to the end of an IEnumerable.</summary>
/// <typeparam name="T">Type of enumerable to return.</typeparam>
/// <returns>IEnumerable containing all the input elements, followed by the
/// specified additional element.</returns>
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T element)
{
if (source == null)
throw new ArgumentNullException("source");
return concatIterator(element, source, false);
}
/// <summary>Adds a single element to the start of an IEnumerable.</summary>
/// <typeparam name="T">Type of enumerable to return.</typeparam>
/// <returns>IEnumerable containing the specified additional element, followed by
/// all the input elements.</returns>
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> tail, T head)
{
if (tail == null)
throw new ArgumentNullException("tail");
return concatIterator(head, tail, true);
}
private static IEnumerable<T> concatIterator<T>(T extraElement,
IEnumerable<T> source, bool insertAtStart)
{
if (insertAtStart)
yield return extraElement;
foreach (var e in source)
yield return e;
if (!insertAtStart)
yield return extraElement;
}
Append<T>
的实现缩短为一行:return source.Concat(Enumerable.Repeat(element, 1));
。 - Stevenhead.AsEnumerable().Concat(source)
/ source.Concat(element.AsEnumerable())
。 - NappyIEnumerable
存储在Session
对象中,并且您正在使用除InProc之外的其他机制(如StateServer或SQLServer),则您的IEnumerable必须是可序列化的。有些人没有意识到这一点,如果他们不知道这一点,可能会出现问题。 - Carlos Muñozparams T[]
,这样你就可以在末尾添加一个或多个项目。 - user1228LINQ to Objects缺少一些理想的特性。
此项目将以符合LINQ精神的方式增强LINQ to Objects并添加额外的方法。
请查看运算符概述维基页面,了解实现的操作符列表。
这肯定是从一些清晰优雅的源代码中学习的好方式。
对于纯粹主义者来说,可能没有什么作用,但它非常有用!
public static void Each<T>(this IEnumerable<T> items, Action<T> action)
{
foreach (var i in items)
action(i);
}
Select
,它是内置的。 - Timwi/// <summary>Creates a <see cref="Queue<T>"/> from an enumerable
/// collection.</summary>
public static Queue<T> ToQueue<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
return new Queue<T>(source);
}
/// <summary>Creates a <see cref="Stack<T>"/> from an enumerable
/// collection.</summary>
public static Stack<T> ToStack<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
return new Stack<T>(source);
}
var myQueue = new Queue<ObjectType>(myObj);
有什么问题吗?对于仅一行的代码,这并不是一个值得的扩展... - cjkToList()
,这些扩展也很好地补充了ToArray()
扩展。我更喜欢流畅的var myQueue = a.SelectMany(...).Where(...).OrderBy(...).ToQueue()
而不是更传统的语法。 - Martin Liversage<ObjectType>
。 - nawfalpublic static bool IsEmpty<T>(this IEnumerable<T> source)
{
return !source.Any();
}
这是两个与SQL相关的C#语言结构
/// <summary>
/// Determines if the source value is contained in the list of possible values.
/// </summary>
/// <typeparam name="T">The type of the objects</typeparam>
/// <param name="value">The source value</param>
/// <param name="values">The list of possible values</param>
/// <returns>
/// <c>true</c> if the source value matches at least one of the possible values; otherwise, <c>false</c>.
/// </returns>
public static bool In<T>(this T value, params T[] values)
{
if (values == null)
return false;
if (values.Contains<T>(value))
return true;
return false;
}
/// <summary>
/// Determines if the source value is contained in the list of possible values.
/// </summary>
/// <typeparam name="T">The type of the objects</typeparam>
/// <param name="value">The source value</param>
/// <param name="values">The list of possible values</param>
/// <returns>
/// <c>true</c> if the source value matches at least one of the possible values; otherwise, <c>false</c>.
/// </returns>
public static bool In<T>(this T value, IEnumerable<T> values)
{
if (values == null)
return false;
if (values.Contains<T>(value))
return true;
return false;
}
/// <summary>
/// Determines if the source value is not contained in the list of possible values.
/// </summary>
/// <typeparam name="T">The type of the objects</typeparam>
/// <param name="value">The source value</param>
/// <param name="values">The list of possible values</param>
/// <returns>
/// <c>false</c> if the source value matches at least one of the possible values; otherwise, <c>true</c>.
/// </returns>
public static bool NotIn<T>(this T value, params T[] values)
{
return In(value, values) == false;
}
/// <summary>
/// Determines if the source value is not contained in the list of possible values.
/// </summary>
/// <typeparam name="T">The type of the objects</typeparam>
/// <param name="value">The source value</param>
/// <param name="values">The list of possible values</param>
/// <returns>
/// <c>false</c> if the source value matches at least one of the possible values; otherwise, <c>true</c>.
/// </returns>
public static bool NotIn<T>(this T value, IEnumerable<T> values)
{
return In(value, values) == false;
}
if (values == null) return false;
。默默地忽略错误条件从来都不是好的做法。 - Timwireturn values.Contains(value);
即可。 - nawfal这个方法与string.Join
基本相同,但有以下不同:
可以在任何集合上使用,而不仅仅是字符串集合(对每个元素调用ToString
)
可以为每个字符串添加前缀和后缀。
作为扩展方法。我发现string.Join
很烦人,因为它是静态的,在一系列操作中它在词法上不是正确的顺序。
/// <summary>
/// Turns all elements in the enumerable to strings and joins them using the
/// specified string as the separator and the specified prefix and suffix for
/// each string.
/// <example>
/// <code>
/// var a = (new[] { "Paris", "London", "Tokyo" }).JoinString(", ", "[", "]");
/// // a contains "[Paris], [London], [Tokyo]"
/// </code>
/// </example>
/// </summary>
public static string JoinString<T>(this IEnumerable<T> values,
string separator = null, string prefix = null, string suffix = null)
{
if (values == null)
throw new ArgumentNullException("values");
using (var enumerator = values.GetEnumerator())
{
if (!enumerator.MoveNext())
return "";
StringBuilder sb = new StringBuilder();
sb.Append(prefix).Append(enumerator.Current.ToString()).Append(suffix);
while (enumerator.MoveNext())
sb.Append(separator).Append(prefix)
.Append(enumerator.Current.ToString()).Append(suffix);
return sb.ToString();
}
}
IEnumerable<string>
的能力。在调用此方法之前,您始终可以将数据投影到IEnumerable<string>
中。 - Christian HayterStringBuilder
之前不需要进行 null
检查。您需要处理枚举器的释放。您可以摆脱循环之上的 Append
调用,并将循环替换为 do-while
。最后,除非您想避免创建 StringBuilder
的成本,否则您不需要将第一个元素视为特殊情况:new StringBuilder().ToString()
将返回 string.Empty
。 - AniAggregate
操作符所没有的功能?这是一个不常用的方法,但绝对可以用于连接对象列表。 - Kirk BroadhurstAggregate
会变慢。但是,即使我想在这种情况下使用Aggregate
,我仍然会将其包装到具有此签名的JoinString
方法中,因为它可以使使用它的代码更清晰。一旦我拥有了它,我也可以通过使用StringBuilder编写更快的方法。 - Timwi/// <summary>
/// Returns a sequence containing one element.
/// </summary>
public static IEnumerable<T> AsIEnumerable<T>(this T obj)
{
yield return obj;
}
使用方法:
var nums = new[] {12, 20, 6};
var numsWith5Prepended = 5.AsIEnumerable().Concat(nums);
return new T[] { obj };
。这样,编译器不必构造一个完整的状态机类来产生一个值。 - Christian Hayternew[]{1, 2, 3, 4}.AsIEnumerable()
的期望是什么?我期望的结果是 1,2,3,4,而不是 [1,2,3,4]。 - larsmoaEnumerableEx.Return(new[]{1, 2, 3, 4})
。你是正确的,“As” 意味着有一些强制转换正在进行,因为数组已经实现了 IEnumerable,所以你期望什么都不会改变。 - Nappy/// <summary>Sorts the elements of a sequence in ascending order.</summary>
public static IEnumerable<T> Order<T>(this IEnumerable<T> source)
{
return source.OrderBy(x => x);
}
List<T>.Sort()
造成歧义。 - AniList<T>.Sort
是原地排序。 - Timwipublic static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
{
var random = new Random();
return items.OrderBy(x => random.Next());
}
编辑:似乎上述实现存在几个问题。这是一个基于@LukeH的代码和@ck和@Strilanc的评论改进版本。
private static Random _rand = new Random();
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
var items = source == null ? new T[] { } : source.ToArray();
var count = items.Length;
while(count > 0)
{
int toReturn = _rand.Next(0, count);
yield return items[toReturn];
items[toReturn] = items[count - 1];
count--;
}
}
OrderBy
是O(n log n),而Fisher-Yates-Durstenfeld shuffle将是O(n)。这里有一个例子:https://dev59.com/z3I-5IYBdhLWcg3w1sPi#1653204 - LukeHFunc<int>
,但必须有人来简化方法获取其伪随机数的方式。 - KeithS