Development Tip

기본 제공되지 않는 가장 좋아하는 LINQ to Objects 연산자는 무엇입니까?

yourdevel 2020. 10. 22. 22:57
반응형

기본 제공되지 않는 가장 좋아하는 LINQ to Objects 연산자는 무엇입니까?


확장 메서드를 사용하면 일반적인 문제를 해결하는 편리한 LINQ 연산자를 작성할 수 있습니다.

System.Linq네임 스페이스 에서 누락 된 메서드 또는 오버로드 와 구현 방법을 듣고 싶습니다 .

기존 방법을 사용하는 깔끔하고 우아한 구현이 선호됩니다.


추가 및 앞에 추가

/// <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;
}

아직 아무도 MoreLINQ 프로젝트를 언급하지 않은 것에 놀랐습니다 . Jon Skeet에 의해 시작되었으며 그 과정에서 일부 개발자를 확보했습니다. 프로젝트 페이지에서 :

LINQ 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);
 }

ToQueue 및 ToStack

/// <summary>Creates a <see cref="Queue&lt;T&gt;"/> 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&lt;T&gt;"/> 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);
}

비었다

public static bool IsEmpty<T>(this IEnumerable<T> source)
{
    return !source.Any();
}

In 및 NotIn

두 개의 다른 잘 알려진 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;
}

AsIEnumerable

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

JoinString

기본적으로와 동일 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();
    }
}

주문

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

혼합

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
{
    var random = new Random();
    return items.OrderBy(x => random.Next());
}

편집 : 위의 구현에 몇 가지 문제가있는 것 같습니다. @ck 및 @Strilanc의 @LukeH 코드 및 주석을 기반으로 한 개선 된 버전이 있습니다.

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--;
    }
}

고리

방금 생각한 멋진 것이 있습니다. ( 방금 생각 했다면 그다지 유용하지 않겠습니까?하지만 용도가 있기 때문에 생각했습니다.) 시퀀스를 반복해서 반복하여 무한 시퀀스를 생성합니다. 이것은 무엇을 등 어떤 종류를 수행 Enumerable.Range하고 Enumerable.Repeat그것을가 사용할 수 있습니다 제외하고 당신을 줄 임의 (달리 Range) 순서 (달리 Repeat) :

public static IEnumerable<T> Loop<T>(this IEnumerable<T> source)
{
    while (true)
    {
        foreach (T item in source)
        {
            yield return item;
        }
    }
}

용법:

var numbers = new[] { 1, 2, 3 };
var looped = numbers.Loop();

foreach (int x in looped.Take(10))
{
    Console.WriteLine(x);
}

산출:

1
2
1
2
1
2
1

참고 : 다음과 같은 방법으로도이 작업을 수행 할 수 있다고 가정합니다.

var looped = Enumerable.Repeat(numbers, int.MaxValue).SelectMany(seq => seq);

...하지만 Loop더 명확 하다고 생각 합니다.


MinElement

Min 지정된 표현식에서 반환 한 최소값 만 반환하고이 최소 요소를 제공 한 원래 요소는 반환하지 않습니다.

/// <summary>Returns the first element from the input sequence for which the
/// value selector returns the smallest value.</summary>
public static T MinElement<T, TValue>(this IEnumerable<T> source,
        Func<T, TValue> valueSelector) where TValue : IComparable<TValue>
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (valueSelector == null)
        throw new ArgumentNullException("valueSelector");
    using (var enumerator = source.GetEnumerator())
    {
        if (!enumerator.MoveNext())
            throw new InvalidOperationException("source contains no elements.");
        T minElem = enumerator.Current;
        TValue minValue = valueSelector(minElem);
        while (enumerator.MoveNext())
        {
            TValue value = valueSelector(enumerator.Current);
            if (value.CompareTo(minValue) < 0)
            {
                minValue = value;
                minElem = enumerator.Current;
            }
        }
        return minElem;
    }
}

IndexOf

/// <summary>
/// Returns the index of the first element in this <paramref name="source"/>
/// satisfying the specified <paramref name="condition"/>. If no such elements
/// are found, returns -1.
/// </summary>
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> condition)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (condition == null)
        throw new ArgumentNullException("condition");
    int index = 0;
    foreach (var v in source)
    {
        if (condition(v))
            return index;
        index++;
    }
    return -1;
}

청크

특정 크기의 청크를 반환합니다. x.Chunks(2)의는 1,2,3,4,5두 개의 배열을 반환 1,2하고 3,4. , x.Chunks(2,true)을 반환 합니다.1,23,45

public static IEnumerable<T[]> Chunks<T>(this IEnumerable<T> xs, int size, bool returnRest = false)
{
    var curr = new T[size];

    int i = 0;

    foreach (var x in xs)
    {
        if (i == size)
        {
            yield return curr;
            i = 0;
            curr = new T[size];
        }

        curr[i++] = x;
    }

    if (returnRest)
        yield return curr.Take(i).ToArray();
}

ToHashSet

public static HashSet<T> ToHashSet<T>(this IEnumerable<T> items)
{
    return new HashSet<T>(items);
}

기본값이 지정된 FirstOrDefault

/// <summary>
/// Returns the first element of a sequence, or a default value if the
/// sequence contains no elements.
/// </summary>
/// <typeparam name="T">The type of the elements of
/// <paramref name="source"/>.</typeparam>
/// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> to return
/// the first element of.</param>
/// <param name="default">The default value to return if the sequence contains
/// no elements.</param>
/// <returns><paramref name="default"/> if <paramref name="source"/> is empty;
/// otherwise, the first element in <paramref name="source"/>.</returns>
public static T FirstOrDefault<T>(this IEnumerable<T> source, T @default)
{
    if (source == null)
        throw new ArgumentNullException("source");
    using (var e = source.GetEnumerator())
    {
        if (!e.MoveNext())
            return @default;
        return e.Current;
    }
}

/// <summary>
/// Returns the first element of a sequence, or a default value if the sequence
/// contains no elements.
/// </summary>
/// <typeparam name="T">The type of the elements of
/// <paramref name="source"/>.</typeparam>
/// <param name="source">The <see cref="IEnumerable&lt;T&gt;"/> to return
/// the first element of.</param>
/// <param name="predicate">A function to test each element for a
/// condition.</param>
/// <param name="default">The default value to return if the sequence contains
/// no elements.</param>
/// <returns><paramref name="default"/> if <paramref name="source"/> is empty
/// or if no element passes the test specified by <paramref name="predicate"/>;
/// otherwise, the first element in <paramref name="source"/> that passes
/// the test specified by <paramref name="predicate"/>.</returns>
public static T FirstOrDefault<T>(this IEnumerable<T> source,
    Func<T, bool> predicate, T @default)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (predicate == null)
        throw new ArgumentNullException("predicate");
    using (var e = source.GetEnumerator())
    {
        while (true)
        {
            if (!e.MoveNext())
                return @default;
            if (predicate(e.Current))
                return e.Current;
        }
    }
}

InsertBetween

연속 된 모든 요소 쌍 사이에 요소를 삽입합니다.

/// <summary>Inserts the specified item in between each element in the input
/// collection.</summary>
/// <param name="source">The input collection.</param>
/// <param name="extraElement">The element to insert between each consecutive
/// pair of elements in the input collection.</param>
/// <returns>A collection containing the original collection with the extra
/// element inserted. For example, new[] { 1, 2, 3 }.InsertBetween(0) returns
/// { 1, 0, 2, 0, 3 }.</returns>
public static IEnumerable<T> InsertBetween<T>(
    this IEnumerable<T> source, T extraElement)
{
    return source.SelectMany(val => new[] { extraElement, val }).Skip(1);
}

EmptyIfNull

이것은 논란의 여지가있는 것입니다. 나는 많은 순수 주의자들이 null성공 에 대한 "인스턴스 방법"에 반대 할 것이라고 확신합니다 .

/// <summary>
/// Returns an IEnumerable<T> as is, or an empty IEnumerable<T> if it is null
/// </summary>
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}    

용법:

foreach(var item in myEnumerable.EmptyIfNull())
{
  Console.WriteLine(item);   
}

구문 분석

여기에는 사용자 지정 대리자가 포함됩니다 ( IParser<T>대신 인터페이스를 사용할 수 있었지만 더 간단했기 때문에 대리자를 사용했습니다). 이는 문자열 시퀀스를 값 시퀀스로 구문 분석하고 구문 분석이 실패한 요소를 건너 뛰는 데 사용됩니다.

public delegate bool TryParser<T>(string text, out T value);

public static IEnumerable<T> Parse<T>(this IEnumerable<string> source,
                                      TryParser<T> parser)
{
    source.ThrowIfNull("source");
    parser.ThrowIfNull("parser");

    foreach (string str in source)
    {
        T value;
        if (parser(str, out value))
        {
            yield return value;
        }
    }
}

용법:

var strings = new[] { "1", "2", "H3llo", "4", "five", "6", "se7en" };
var numbers = strings.Parse<int>(int.TryParse);

foreach (int x in numbers)
{
    Console.WriteLine(x);
}

산출:

1
2
4
6

이것에 대한 이름 지정은 까다 롭습니다. 내가인지 확실하지 않다 Parse최선의 선택은 (그것이 이다 적어도, 간단한), 또는 같은 것을하면 ParseWhereValid더 좋을 것이다.


ZipMerge

이것은 Zip실제 지퍼처럼 작동하는 내 버전입니다 . 두 값을 하나로 투영하지 않고 결합 된 IEnumerable을 반환합니다. 과부하, 오른쪽 및 / 또는 왼쪽 꼬리를 건너 뛸 수 있습니다.

public static IEnumerable<TSource> ZipMerge<TSource>(
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second)
{
    using (var secondEnumerator = second.GetEnumerator())
    {
        foreach (var item in first)
        {
            yield return item;

            if (secondEnumerator.MoveNext())
                yield return secondEnumerator.Current;
        }

        while (secondEnumerator.MoveNext())
            yield return secondEnumerator.Current;
    }
}

무작위 샘플

다음은 중간 규모의 데이터 집합 (예 : 100 개 이상의 항목)이 있고 그 데이터를 무작위로 샘플링하려는 경우에 유용한 간단한 함수입니다.

public static IEnumerable<T> RandomSample<T>(this IEnumerable<T> source,
                                             double percentage)
{
    source.ThrowIfNull("source");

    var r = new Random();
    return source.Where(x => (r.NextDouble() * 100.0) < percentage);
}

용법:

List<DataPoint> data = GetData();

// Sample roughly 3% of the data
var sample = data.RandomSample(3.0);

// Verify results were correct for this sample
foreach (DataPoint point in sample)
{
    Console.WriteLine("{0} => {1}", point, DoCalculation(point));
}

메모:

  1. 반환되는 항목 수가 확률 적이므로 작은 컬렉션에는 적합하지 않습니다 (작은 시퀀스에서 쉽게 0을 반환 할 수 있음).
  2. 시퀀스의 모든 항목을 열거하는 것이 포함되므로 대규모 컬렉션이나 데이터베이스 쿼리에는 적합하지 않습니다.

AssertCount

IEnumerable<T>에 최소한 / 정확하게 / 최대 특정 수의 요소 포함되어 있는지 효율적으로 결정합니다 .

public enum CountAssertion
{
    AtLeast,
    Exact,
    AtMost
}

/// <summary>
/// Asserts that the number of items in a sequence matching a specified predicate satisfies a specified CountAssertion.
/// </summary>
public static bool AssertCount<T>(this IEnumerable<T> source, int countToAssert, CountAssertion assertion, Func<T, bool> predicate)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (predicate == null)
        throw new ArgumentNullException("predicate");

    return source.Where(predicate).AssertCount(countToAssert, assertion);
}

/// <summary>
/// Asserts that the number of elements in a sequence satisfies a specified CountAssertion.
/// </summary>
public static bool AssertCount<T>(this IEnumerable<T> source, int countToAssert, CountAssertion assertion)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (countToAssert < 0)
        throw new ArgumentOutOfRangeException("countToAssert");    

    switch (assertion)
    {
        case CountAssertion.AtLeast:
            return AssertCountAtLeast(source, GetFastCount(source), countToAssert);

        case CountAssertion.Exact:
            return AssertCountExact(source, GetFastCount(source), countToAssert);

        case CountAssertion.AtMost:
            return AssertCountAtMost(source, GetFastCount(source), countToAssert);

        default:
            throw new ArgumentException("Unknown CountAssertion.", "assertion");
    }

}

private static int? GetFastCount<T>(IEnumerable<T> source)
{
    var genericCollection = source as ICollection<T>;
    if (genericCollection != null)
        return genericCollection.Count;

    var collection = source as ICollection;
    if (collection != null)
        return collection.Count;

    return null;
}

private static bool AssertCountAtMost<T>(IEnumerable<T> source, int? fastCount, int countToAssert)
{
    if (fastCount.HasValue)
        return fastCount.Value <= countToAssert;

    int countSoFar = 0;

    foreach (var item in source)
    {
        if (++countSoFar > countToAssert) return false;
    }

    return true;
}

private static bool AssertCountExact<T>(IEnumerable<T> source, int? fastCount, int countToAssert)
{
    if (fastCount.HasValue)
        return fastCount.Value == countToAssert;

    int countSoFar = 0;

    foreach (var item in source)
    {
        if (++countSoFar > countToAssert) return false;
    }

    return countSoFar == countToAssert;
}

private static bool AssertCountAtLeast<T>(IEnumerable<T> source, int? fastCount, int countToAssert)
{
    if (countToAssert == 0)
        return true;

    if (fastCount.HasValue)
        return fastCount.Value >= countToAssert;

    int countSoFar = 0;

    foreach (var item in source)
    {
        if (++countSoFar >= countToAssert) return true;
    }

    return false;
}

사용법 :

var nums = new[] { 45, -4, 35, -12, 46, -98, 11 };
bool hasAtLeast3Positive = nums.AssertCount(3, CountAssertion.AtLeast, i => i > 0); //true
bool hasAtMost1Negative = nums.AssertCount(1, CountAssertion.AtMost, i => i < 0); //false
bool hasExactly2Negative = nums.AssertCount(2, CountAssertion.Exact, i => i < 0); //false

창문

size최신 값 포함하는 길이로 배열 ( "windows")을 열거 합니다.
{ 0, 1, 2, 3 }로됩니다 { [0, 1], [1, 2], [2, 3] }.

예를 들어 두 점을 연결하여 선 그래프를 그리는 데 이것을 사용하고 있습니다.

public static IEnumerable<TSource[]> Window<TSource>(
    this IEnumerable<TSource> source)
{
    return source.Window(2);
}

public static IEnumerable<TSource[]> Window<TSource>(
    this IEnumerable<TSource> source, int size)
{
    if (size <= 0)
        throw new ArgumentOutOfRangeException("size");

    return source.Skip(size).WindowHelper(size, source.Take(size));
}

private static IEnumerable<TSource[]> WindowHelper<TSource>(
    this IEnumerable<TSource> source, int size, IEnumerable<TSource> init)
{
    Queue<TSource> q = new Queue<TSource>(init);

    yield return q.ToArray();

    foreach (var value in source)
    {
        q.Dequeue();
        q.Enqueue(value);
        yield return q.ToArray();
    }
}

하나, 둘, MoreThanOne, AtLeast, AnyAtAll

public static bool One<T>(this IEnumerable<T> enumerable)
{
    using (var enumerator = enumerable.GetEnumerator())
        return enumerator.MoveNext() && !enumerator.MoveNext();
}

public static bool Two<T>(this IEnumerable<T> enumerable)
{
    using (var enumerator = enumerable.GetEnumerator())
        return enumerator.MoveNext() && enumerator.MoveNext() && !enumerator.MoveNext();
}

public static bool MoreThanOne<T>(this IEnumerable<T> enumerable)
{
    return enumerable.Skip(1).Any();
}

public static bool AtLeast<T>(this IEnumerable<T> enumerable, int count)
{
    using (var enumerator = enumerable.GetEnumerator())
        for (var i = 0; i < count; i++)
            if (!enumerator.MoveNext())
                return false;
    return true;
}

public static bool AnyAtAll<T>(this IEnumerable<T> enumerable)
{
    return enumerable != null && enumerable.Any();
}

SkipLast 및 TakeLast

/// <summary>
/// Enumerates the items of this collection, skipping the last
/// <paramref name="count"/> items. Note that the memory usage of this method
/// is proportional to <paramref name="count"/>, but the source collection is
/// only enumerated once, and in a lazy fashion. Also, enumerating the first
/// item will take longer than enumerating subsequent items.
/// </summary>
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (count < 0)
        throw new ArgumentOutOfRangeException("count",
            "count cannot be negative.");
    if (count == 0)
        return source;
    return skipLastIterator(source, count);
}
private static IEnumerable<T> skipLastIterator<T>(IEnumerable<T> source,
    int count)
{
    var queue = new T[count];
    int headtail = 0; // tail while we're still collecting, both head & tail
                      // afterwards because the queue becomes completely full
    int collected = 0;

    foreach (var item in source)
    {
        if (collected < count)
        {
            queue[headtail] = item;
            headtail++;
            collected++;
        }
        else
        {
            if (headtail == count) headtail = 0;
            yield return queue[headtail];
            queue[headtail] = item;
            headtail++;
        }
    }
}

/// <summary>
/// Returns a collection containing only the last <paramref name="count"/>
/// items of the input collection. This method enumerates the entire
/// collection to the end once before returning. Note also that the memory
/// usage of this method is proportional to <paramref name="count"/>.
/// </summary>
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
    if (source == null)
        throw new ArgumentNullException("source");
    if (count < 0)
        throw new ArgumentOutOfRangeException("count",
            "count cannot be negative.");
    if (count == 0)
        return new T[0];

    var queue = new Queue<T>(count + 1);
    foreach (var item in source)
    {
        if (queue.Count == count)
            queue.Dequeue();
        queue.Enqueue(item);
    }
    return queue.AsEnumerable();
}

중복

Ani의 AssertCount메서드 ( 라는 메서드를 사용합니다)와 같은 메서드와 함께 사용 CountAtLeast하면 두 번 이상 나타나는 시퀀스에서 요소를 매우 쉽게 찾을 수 있습니다.

public static IEnumerable<T> Duplicates<T, TKey>(this IEnumerable<T> source,
    Func<T, TKey> keySelector = null, IEqualityComparer<TKey> comparer = null)
{
    source.ThrowIfNull("source");
    keySelector = keySelector ?? new Func<T, TKey>(x => x);
    comparer = comparer ?? EqualityComparer<TKey>.Default;

    return source.GroupBy(keySelector, comparer)
        .Where(g => g.CountAtLeast(2))
        .SelectMany(g => g);
}

어디에

Where에 대한 선택적 . 쿼리에 대한 조건 자와 람다를 빌드 할 때 if 문을 사용하지 않습니다. 컴파일 타임에 필터 적용 여부를 모를 때 유용합니다.IEnumerableIQueryable

public static IEnumerable<TSource> WhereIf<TSource>(
            this IEnumerable<TSource> source, bool condition,
            Func<TSource, bool> predicate)
{
    return condition ? source.Where(predicate) : source;
}

사용법 :

var custs = Customers.WhereIf(someBool, x=>x.EyeColor=="Green");

LINQ WhereIf At ExtensionMethod.NET 이며 Andrew의 블로그 에서 빌 렸습니다 .


초기 용량이있는 ToList 및 ToDictionary

기본 컬렉션 클래스의 초기 용량을 노출하는 ToList 및 ToDictionary 오버로드. 소스 길이가 알려 지거나 제한되어있을 때 가끔 유용합니다.

public static List<TSource> ToList<TSource>(
    this IEnumerable<TSource> source, 
    int capacity)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    var list = new List<TSource>(capacity);
    list.AddRange(source);
    return list;
}     

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    int capacity,
    IEqualityComparer<TKey> comparer = null)
{
    return source.ToDictionary<TSource, TKey, TSource>(
                  keySelector, x => x, capacity, comparer);
}

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    Func<TSource, TElement> elementSelector,
    int capacity,
    IEqualityComparer<TKey> comparer = null)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    if (keySelector == null)
    {
        throw new ArgumentNullException("keySelector");
    }
    if (elementSelector == null)
    {
        throw new ArgumentNullException("elementSelector");
    }
    var dictionary = new Dictionary<TKey, TElement>(capacity, comparer);
    foreach (TSource local in source)
    {
        dictionary.Add(keySelector(local), elementSelector(local));
    }
    return dictionary;
}

CountUpTo

static int CountUpTo<T>(this IEnumerable<T> source, int maxCount)
{
    if (maxCount == 0)
        return 0;

    var genericCollection = source as ICollection<T>; 
    if (genericCollection != null) 
        return Math.Min(maxCount, genericCollection.Count);

    var collection = source as ICollection; 
    if (collection != null)
        return Math.Min(maxCount, collection.Count);

    int count = 0;
    foreach (T item in source)
        if (++count >= maxCount)
            break;
    return count;
}

합체

public static T Coalesce<T>(this IEnumerable<T> items) {
   return items.Where(x => x != null && !x.Equals(default(T))).FirstOrDefault();
   // return items.OfType<T>().FirstOrDefault(); // Gabe's take
}

참고URL : https://stackoverflow.com/questions/3645644/whats-your-favorite-linq-to-objects-operator-which-is-not-built-in

반응형