Linq를 사용하여 컬렉션의 마지막 N 개 요소를 가져 오십니까?


284

컬렉션이 주어지면 해당 컬렉션의 마지막 N 요소를 얻는 방법이 있습니까? 프레임 워크에 메소드가 없다면 확장 메소드를 작성하는 가장 좋은 방법은 무엇입니까?

답변:


422
collection.Skip(Math.Max(0, collection.Count() - N));

이 접근 방식은 정렬에 의존하지 않고 항목 순서를 유지하며 여러 LINQ 공급자간에 광범위하게 호환됩니다.

Skip음수 로 전화하지 않도록주의해야합니다 . Entity Framework와 같은 일부 공급자는 부정적인 인수가 표시되면 ArgumentException을 생성합니다. Math.Max깔끔하게 피하 라는 부름 .

아래 클래스에는 확장 메소드에 대한 모든 필수 사항이 있습니다. 정적 메소드, 정적 메소드 및 this키워드 사용입니다 .

public static class MiscExtensions
{
    // Ex: collection.TakeLast(5);
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int N)
    {
        return source.Skip(Math.Max(0, source.Count() - N));
    }
}

성능에 대한 간단한 참고 사항 :

호출하면 Count()특정 데이터 구조가 열거 될 수 있으므로이 접근 방식은 데이터를 두 번 통과시킬 위험이 있습니다. 이것은 실제로 대부분의 열거 가능한 문제가 아닙니다. 실제로 Count()O (1) 시간 내에 연산 을 평가하기 위해 목록, 배열 및 EF 쿼리에 대한 최적화가 이미 존재합니다 .

그러나 순방향 전용 열거 형을 사용해야하고 두 번의 통과를 피하려면 Lasse V. Karlsen 또는 Mark Byers 와 같은 단일 패스 알고리즘을 고려하십시오 . 이 두 가지 접근 방법은 열거하는 동안 항목을 보유하기 위해 임시 버퍼를 사용하며, 콜렉션의 끝이 발견되면 생성됩니다.


2
Linq to Entities / SQL에서 작동하므로 +1입니다. Linq to Objects에서 James Curran의 전략보다 성능이 뛰어나다 고 생각합니다.
StriplingWarrior

11
수집의 특성에 따라 다릅니다. Count ()는 O (N) 일 수 있습니다.
James Curran

3
@ 제임스 : 맞습니다. IEnumerable 컬렉션을 엄격하게 다루는 경우 2 패스 쿼리가 될 수 있습니다. 보장 된 1 패스 알고리즘을 보는 데 매우 관심이 있습니다. 유용 할 수 있습니다.
kbrimington

4
몇 가지 벤치 마크를했습니다. LINQ to Objects는 사용중인 컬렉션 유형에 따라 일부 최적화를 수행합니다. James의 솔루션은 배열, Lists 및 LinkedLists를 사용하면 수십 배는 아니지만 더 빠른 경향이 있습니다. IEnumerable이 (Enumerable.Range 등을 통해) 계산되면 James의 솔루션이 더 오래 걸립니다. 구현에 대해 알지 못하거나 다른 데이터 구조에 값을 복사하지 않고 단일 패스를 보장하는 방법을 생각할 수 없습니다.
StriplingWarrior

1
@RedFilter-충분합니다. 페이징 습관이 여기서 유출되었다고 생각합니다. 예리한 눈에 감사드립니다.
kbrimington

59
coll.Reverse().Take(N).Reverse().ToList();


public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> coll, int N)
{
    return coll.Reverse().Take(N).Reverse();
}

업데이트 : clintp의 문제를 해결하려면 : a) 위에서 정의한 TakeLast () 메소드를 사용하면 문제가 해결되지만 추가 메소드없이 실제로 수행하려면 Enumerable.Reverse ()가 될 수 있음을 인식해야합니다. 확장 방법으로 사용되면 다음과 같이 사용할 필요가 없습니다.

List<string> mystring = new List<string>() { "one", "two", "three" }; 
mystring = Enumerable.Reverse(mystring).Take(2).Reverse().ToList();

:이 함께이 문제는 내가 말할 경우입니다 List<string> mystring = new List<string>() { "one", "two", "three" }; mystring = mystring.Reverse().Take(2).Reverse(); .Reverse ()를 무효 반환 및 컴파일러이 선택하는 대신는 IEnumerable을 반환 Linq에 하나의 방법 때문에 나는 컴파일러 오류가 발생합니다. 제안?
클린턴 피어스

1
당신은 명시 적으로는 IEnumerable <문자열>에 mystring에 캐스팅하여이 문제를 해결할 수 있습니다 : ((는 IEnumerable <문자열>)을 MyString) .Reverse는 () (2) .Reverse를 타고 ().
월 HETTICH

쉽고 간단하지만 주문을 두 번 완전히 되돌려 야합니다. 이것이 가장 좋은 방법
shashwat

나는 kbrimington의 대답에 덧붙여 그것을 좋아합니다. 마지막 N레코드를 얻은 후 주문에 신경 쓰지 않으면 두 번째 레코드를 건너 뛸 수 있습니다 Reverse.
ZoolWay

@shashwat 순서를 "완전히"두 번 바꾸지 않습니다. 두 번째 반전은 N 개의 아이템 수집에만 적용됩니다. 또한 Reverse ()가 구현되는 방식에 따라 첫 번째 호출은 N 개의 항목 만 되돌릴 수 있습니다. (.NET 4.0 구현은 컬렉션을 배열에 복사하고 그것을 뒤로 색인화합니다)
James Curran

47

참고 : Linq 사용 이라는 질문 제목을 놓쳤 으므로 실제로 Linq를 사용하지 않습니다.

전체 컬렉션의 지연되지 않은 복사본을 캐싱하지 않으려면 연결된 목록을 사용하여 간단한 방법을 작성할 수 있습니다.

다음 방법은 원본 컬렉션에서 찾은 각 값을 연결 목록에 추가하고 연결 목록을 필요한 항목 수로 줄입니다. 컬렉션을 반복하는 동안 링크 된 목록이이 항목 수만큼 잘린 상태로 유지되므로 원본 컬렉션에서 최대 N 개의 항목 복사본 만 유지합니다.

원본 컬렉션의 항목 수를 알 필요가 없으며 여러 번 반복하지 않아도됩니다.

용법:

IEnumerable<int> sequence = Enumerable.Range(1, 10000);
IEnumerable<int> last10 = sequence.TakeLast(10);
...

확장 방법 :

public static class Extensions
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> collection,
        int n)
    {
        if (collection == null)
            throw new ArgumentNullException(nameof(collection));
        if (n < 0)
            throw new ArgumentOutOfRangeException(nameof(n), $"{nameof(n)} must be 0 or greater");

        LinkedList<T> temp = new LinkedList<T>();

        foreach (var value in collection)
        {
            temp.AddLast(value);
            if (temp.Count > n)
                temp.RemoveFirst();
        }

        return temp;
    }
}

Linq를 기술적으로 사용하지 않더라도 여전히 타당한 답변이 있다고 생각합니다. 그래서 나는 여전히 +1을 제공합니다 :)
Matthew Groves

깨끗하고 깔끔하며 확장 가능한 +1!
Yasser Shaikh

1
소스 열거자가 두 번 이상 실행되지 않고 열거의 구체화를 강요하지 않는 유일한 솔루션이라고 생각합니다. 따라서 대부분의 응용 프로그램에서 훨씬 효율적이라고 말할 것입니다. 기억과 속도.
Sprotty

30

열거 가능한 모든 작업에서 작동하지만 O (N) 임시 저장소 만 사용하는 방법은 다음과 같습니다.

public static class TakeLastExtension
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int takeCount)
    {
        if (source == null) { throw new ArgumentNullException("source"); }
        if (takeCount < 0) { throw new ArgumentOutOfRangeException("takeCount", "must not be negative"); }
        if (takeCount == 0) { yield break; }

        T[] result = new T[takeCount];
        int i = 0;

        int sourceCount = 0;
        foreach (T element in source)
        {
            result[i] = element;
            i = (i + 1) % takeCount;
            sourceCount++;
        }

        if (sourceCount < takeCount)
        {
            takeCount = sourceCount;
            i = 0;
        }

        for (int j = 0; j < takeCount; ++j)
        {
            yield return result[(i + j) % takeCount];
        }
    }
}

용법:

List<int> l = new List<int> {4, 6, 3, 6, 2, 5, 7};
List<int> lastElements = l.TakeLast(3).ToList();

N 크기의 링 버퍼를 사용하여 요소를 볼 때 저장하여 이전 요소를 새 요소로 덮어 씁니다. 열거 가능 항목의 끝에 도달하면 링 버퍼에 마지막 N 개의 요소가 포함됩니다.


2
+1 :이 방법은 내 것보다 성능이 좋아야하지만 컬렉션에보다 적은 수의 요소가 포함 된 경우 올바른 작업을 수행해야합니다 n.
Lasse V. Karlsen

글쎄, 대부분 사람들이 SO를 코드를 복사 할 때 프로덕션 용도로 코드를 복사 할 때 사람들이주의를 기울일 것이라고 가정하는 경우 문제가되지 않을 수 있습니다. 추가하려는 경우 컬렉션 변수도 null인지 확인하십시오. 그렇지 않으면, 훌륭한 해결책 :) 링크 된 목록이 GC 압력을 추가하기 때문에 링 버퍼를 사용하는 것을 고려하고 있었지만, 한 번 수행 한 지 오래되었지만 테스트 코드로 번거롭게하고 싶지 않았습니다. 내가 제대로했다면 내가 생각 :) LINQPad와 사랑에 빠졌어 말을해야 linqpad.net
라세 V. 칼슨

2
가능한 최적화는 열거 가능한 IList가 구현되었는지 확인하고 사소한 솔루션을 사용하는 것입니다. 임시 저장 방법은 IEnumerables를
실제로

1
사소한 니트-선택 : ArgumentOutOfRangeException에 대한 당신의 주장은 잘못된 순서입니다 (R # 말한다)
piers7

28

.NET Core 2.0+는 LINQ 방법을 제공합니다 TakeLast().

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.takelast

:

Enumerable
    .Range(1, 10)
    .TakeLast(3) // <--- takes last 3 items
    .ToList()
    .ForEach(i => System.Console.WriteLine(i))

// outputs:
// 8
// 9
// 10

: NET Standard 2.0을 사용하고 있으며 사용할 수 없습니다. 뭐가 문제 야? :(
SuperJMN

@SuperJMN .net 표준 2.0 라이브러리를 참조하더라도 프로젝트에서 올바른 버전의 닷넷 코어를 대상으로하지 않을 수 있습니다. 이 방법은 v1.x ( netcoreapp1.x) 에는 사용할 수 없지만 dotnetcore ( netcoreapp2.x) 의 v2.0 및 v2.1에만 사용할 수 있습니다 . net472지원되지 않는 전체 프레임 워크 (예 :)를 타겟팅 할 수도 있습니다. (.net 표준 라이브러리는 위의 방법으로 사용할 수 있지만 대상 프레임 워크에 특정한 특정 API 만 노출 할 수 있습니다. docs.microsoft.com/en-us/dotnet/standard/frameworks 참조 )
Ray

1
이것들은 지금 더 높아야합니다. 필요 바퀴 재 - 발명 없습니다
제임스 우 들리

11

아무도 언급하지 않았지만 SkipWhile에는 요소의 index사용 하는 메소드가 있습니다 .

public static IEnumerable<T> TakeLastN<T>(this IEnumerable<T> source, int n)
{
    if (source == null)
        throw new ArgumentNullException("Source cannot be null");

    int goldenIndex = source.Count() - n;
    return source.SkipWhile((val, index) => index < goldenIndex);
}

//Or if you like them one-liners (in the spirit of the current accepted answer);
//However, this is most likely impractical due to the repeated calculations
collection.SkipWhile((val, index) => index < collection.Count() - N)

이 솔루션이 다른 솔루션보다 유일하게 인식 할 수있는 이점은 IEnumerable을 두 번 통과하는 두 개의 별도 작업을 수행하는 대신보다 강력하고 효율적인 LINQ 쿼리를 만들기 위해 조건자를 추가 할 수 있다는 것입니다.

public static IEnumerable<T> FilterLastN<T>(this IEnumerable<T> source, int n, Predicate<T> pred)
{
    int goldenIndex = source.Count() - n;
    return source.SkipWhile((val, index) => index < goldenIndex && pred(val));
}

9

RX의 System.Interactive 어셈블리에서 EnumerableEx.TakeLast를 사용하십시오. @Mark와 같은 O (N) 구현이지만 링 버퍼 구문 대신 대기열을 사용합니다 (버퍼 용량에 도달하면 항목을 대기열에서 제외).

(NB : 이것은 IEnumerable 버전입니다. IObservable 버전은 아닙니다. 두 버전의 구현은 거의 동일합니다)


이것이 가장 좋은 대답입니다. 작업을 수행하는 데 적합한 라이브러리가 있고 RX 팀의 품질이 높은 경우 직접 롤링하지 마십시오.
bradgonesurfing 2019

-이 함께가는 경우, Nuget에서 설치 nuget.org/packages/Ix-Async
nikib3ro

순환 버퍼를Queue<T> 사용하여 C #을 구현 하지 않습니까?
tigrou

@tigrou. 아니, 그것은 원형이 아니다
citykid


6

키가있는 컬렉션 (예 : 데이터베이스의 항목)을 처리하는 경우 빠른 (즉, 선택한 답변보다 빠름) 솔루션은 다음과 같습니다.

collection.OrderByDescending(c => c.Key).Take(3).OrderBy(c => c.Key);

+1은 저에게 효과적이며 읽기 쉽습니다. 목록에 적은 수의 객체가 있습니다
fubo

5

모나드의 일부로 Rx를 담그는 것이 마음에 들지 않으면 다음을 사용할 수 있습니다 TakeLast.

IEnumerable<int> source = Enumerable.Range(1, 10000);

IEnumerable<int> lastThree = source.AsObservable().TakeLast(3).AsEnumerable();

2
System.Reactive 대신 RX의 System.Interactive를 참조하면 AsObservable ()이 필요하지 않습니다 (내 답변 참조)
piers7

2

타사 라이브러리를 사용하는 것이 옵션 인 경우 MoreLinqTakeLast()정확히 어떤 기능을 수행 하는지 정의 합니다.


2

나는 효율성과 단순성을 결합하려고 노력했으며 이것으로 끝났습니다.

public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
    if (source == null) { throw new ArgumentNullException("source"); }

    Queue<T> lastElements = new Queue<T>();
    foreach (T element in source)
    {
        lastElements.Enqueue(element);
        if (lastElements.Count > count)
        {
            lastElements.Dequeue();
        }
    }

    return lastElements;
}

성능 정보 : C #에서는 순환 버퍼를Queue<T> 사용하여 구현 되므로 각 루프에서 수행되는 객체 인스턴스화가 없습니다 (큐가 커질 때만). 누군가이 확장을 호출 할 수 있기 때문에 (전용 생성자를 사용하여) 대기열 용량을 설정하지 않았습니다 . 추가 성능을 위해 소스 구현인지 확인 하고 예인 경우 배열 인덱스를 사용하여 마지막 값을 직접 추출하십시오.count = int.MaxValueIList<T>


1

위의 모든 솔루션에서 컬렉션 전체를 반복해야하므로 LINQ를 사용하여 컬렉션의 마지막 N 개를 가져 오는 것은 약간 비효율적입니다. TakeLast(int n)의는 System.Interactive이 문제가 있습니다.

목록이 더 효율적인 경우 다음 방법을 사용하여 목록을 슬라이스하십시오.

/// Select from start to end exclusive of end using the same semantics
/// as python slice.
/// <param name="list"> the list to slice</param>
/// <param name="start">The starting index</param>
/// <param name="end">The ending index. The result does not include this index</param>
public static List<T> Slice<T>
(this IReadOnlyList<T> list, int start, int? end = null)
{
    if (end == null)
    {
        end = list.Count();
    }
     if (start < 0)
    {
        start = list.Count + start;
    }
     if (start >= 0 && end.Value > 0 && end.Value > start)
    {
        return list.GetRange(start, end.Value - start);
    }
     if (end < 0)
    {
        return list.GetRange(start, (list.Count() + end.Value) - start);
    }
     if (end == start)
    {
        return new List<T>();
    }
     throw new IndexOutOfRangeException(
        "count = " + list.Count() + 
        " start = " + start +
        " end = " + end);
}

public static List<T> GetRange<T>( this IReadOnlyList<T> list, int index, int count )
{
    List<T> r = new List<T>(count);
    for ( int i = 0; i < count; i++ )
    {
        int j=i + index;
        if ( j >= list.Count )
        {
            break;
        }
        r.Add(list[j]);
    }
    return r;
}

일부 테스트 사례

[Fact]
public void GetRange()
{
    IReadOnlyList<int> l = new List<int>() { 0, 10, 20, 30, 40, 50, 60 };
     l
        .GetRange(2, 3)
        .ShouldAllBeEquivalentTo(new[] { 20, 30, 40 });
     l
        .GetRange(5, 10)
        .ShouldAllBeEquivalentTo(new[] { 50, 60 });

}
 [Fact]
void SliceMethodShouldWork()
{
    var list = new List<int>() { 1, 3, 5, 7, 9, 11 };
    list.Slice(1, 4).ShouldBeEquivalentTo(new[] { 3, 5, 7 });
    list.Slice(1, -2).ShouldBeEquivalentTo(new[] { 3, 5, 7 });
    list.Slice(1, null).ShouldBeEquivalentTo(new[] { 3, 5, 7, 9, 11 });
    list.Slice(-2)
        .Should()
        .BeEquivalentTo(new[] {9, 11});
     list.Slice(-2,-1 )
        .Should()
        .BeEquivalentTo(new[] {9});
}

1

이 질문에 답하기에는 늦었다는 것을 알고 있습니다. 그러나 IList <> 형식의 컬렉션을 사용하고 있고 반환 된 컬렉션의 순서를 신경 쓰지 않으면이 방법이 더 빨리 작동합니다. Mark Byers의 답변을 사용 하고 약간 변경했습니다. 이제 TakeLast 메소드는 다음과 같습니다.

public static IEnumerable<T> TakeLast<T>(IList<T> source, int takeCount)
{
    if (source == null) { throw new ArgumentNullException("source"); }
    if (takeCount < 0) { throw new ArgumentOutOfRangeException("takeCount", "must not be negative"); }
    if (takeCount == 0) { yield break; }

    if (source.Count > takeCount)
    {
        for (int z = source.Count - 1; takeCount > 0; z--)
        {
            takeCount--;
            yield return source[z];
        }
    }
    else
    {
        for(int i = 0; i < source.Count; i++)
        {
            yield return source[i];
        }
    }
}

테스트를 위해 Mark Byers 방법과 kbrimington 's andswer을 사용했습니다 . 이것은 테스트입니다.

IList<int> test = new List<int>();
for(int i = 0; i<1000000; i++)
{
    test.Add(i);
}

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

IList<int> result = TakeLast(test, 10).ToList();

stopwatch.Stop();

Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();

IList<int> result1 = TakeLast2(test, 10).ToList();

stopwatch1.Stop();

Stopwatch stopwatch2 = new Stopwatch();
stopwatch2.Start();

IList<int> result2 = test.Skip(Math.Max(0, test.Count - 10)).Take(10).ToList();

stopwatch2.Stop();

다음은 10 가지 요소를 사용한 결과입니다.

여기에 이미지 설명을 입력하십시오

그리고 1000001 요소를 취한 결과는 다음과 같습니다. 여기에 이미지 설명을 입력하십시오


1

내 해결책은 다음과 같습니다.

public static class EnumerationExtensions
{
    public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> input, int count)
    {
        if (count <= 0)
            yield break;

        var inputList = input as IList<T>;

        if (inputList != null)
        {
            int last = inputList.Count;
            int first = last - count;

            if (first < 0)
                first = 0;

            for (int i = first; i < last; i++)
                yield return inputList[i];
        }
        else
        {
            // Use a ring buffer. We have to enumerate the input, and we don't know in advance how many elements it will contain.
            T[] buffer = new T[count];

            int index = 0;

            count = 0;

            foreach (T item in input)
            {
                buffer[index] = item;

                index = (index + 1) % buffer.Length;
                count++;
            }

            // The index variable now points at the next buffer entry that would be filled. If the buffer isn't completely
            // full, then there are 'count' elements preceding index. If the buffer *is* full, then index is pointing at
            // the oldest entry, which is the first one to return.
            //
            // If the buffer isn't full, which means that the enumeration has fewer than 'count' elements, we'll fix up
            // 'index' to point at the first entry to return. That's easy to do; if the buffer isn't full, then the oldest
            // entry is the first one. :-)
            //
            // We'll also set 'count' to the number of elements to be returned. It only needs adjustment if we've wrapped
            // past the end of the buffer and have enumerated more than the original count value.

            if (count < buffer.Length)
                index = 0;
            else
                count = buffer.Length;

            // Return the values in the correct order.
            while (count > 0)
            {
                yield return buffer[index];

                index = (index + 1) % buffer.Length;
                count--;
            }
        }
    }

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> input, int count)
    {
        if (count <= 0)
            return input;
        else
            return input.SkipLastIter(count);
    }

    private static IEnumerable<T> SkipLastIter<T>(this IEnumerable<T> input, int count)
    {
        var inputList = input as IList<T>;

        if (inputList != null)
        {
            int first = 0;
            int last = inputList.Count - count;

            if (last < 0)
                last = 0;

            for (int i = first; i < last; i++)
                yield return inputList[i];
        }
        else
        {
            // Aim to leave 'count' items in the queue. If the input has fewer than 'count'
            // items, then the queue won't ever fill and we return nothing.

            Queue<T> elements = new Queue<T>();

            foreach (T item in input)
            {
                elements.Enqueue(item);

                if (elements.Count > count)
                    yield return elements.Dequeue();
            }
        }
    }
}

코드는 약간 엉성하지만 재사용이 가능한 드롭 인 구성 요소로 대부분의 시나리오에서 가능한 한 잘 수행해야하며 코드를 사용하는 코드를 간결하고 간결하게 유지합니다. :-)

My TakeLastfor non- IList`1은 @Mark Byers 및 @MackieChan의 답변과 동일한 링 버퍼 알고리즘을 기반으로합니다. 그것들이 얼마나 비슷한 지 흥미 롭습니다. 저는 완전히 독립적으로 글을 썼습니다. 링 버퍼를 올바르게 수행하는 유일한 방법이 있다고 생각합니다. :-)

@kbrimington의 답변을 살펴보면 IQuerable<T>Entity Framework와 잘 작동하는 접근법으로 돌아 가기 위해 추가 검사를 추가 할 수 있습니다 .이 시점에서 내가 가지고있는 것이 그렇지 않다고 가정합니다.


0

실제 예제 아래에서 컬렉션 (어레이)에서 마지막 3 개 요소를 가져 오는 방법 :

// split address by spaces into array
string[] adrParts = adr.Split(new string[] { " " },StringSplitOptions.RemoveEmptyEntries);
// take only 3 last items in array
adrParts = adrParts.SkipWhile((value, index) => { return adrParts.Length - index > 3; }).ToArray();

0

이 방법을 사용하여 오류없이 모든 범위 가져 오기

 public List<T> GetTsRate( List<T> AllT,int Index,int Count)
        {
            List<T> Ts = null;
            try
            {
                Ts = AllT.ToList().GetRange(Index, Count);
            }
            catch (Exception ex)
            {
                Ts = AllT.Skip(Index).ToList();
            }
            return Ts ;
        }

0

순환 버퍼 사용으로 거의 다른 구현. 벤치 마크에 따르면이 방법은 Queue ( System.Linq 에서 TakeLast 구현)를 사용하는 방법보다 2 배 빠릅니다 . 비용이 들지 않습니다. 작은 컬렉션은 거대한 메모리 할당을 얻을 수 있습니다.

public IEnumerable<T> TakeLast<T>(IEnumerable<T> source, int count)
{
    int i = 0;

    if (count < 1)
        yield break;

    if (source is IList<T> listSource)
    {
        if (listSource.Count < 1)
            yield break;

        for (i = listSource.Count < count ? 0 : listSource.Count - count; i < listSource.Count; i++)
            yield return listSource[i];

    }
    else
    {
        bool move = true;
        bool filled = false;
        T[] result = new T[count];

        using (var enumerator = source.GetEnumerator())
            while (move)
            {
                for (i = 0; (move = enumerator.MoveNext()) && i < count; i++)
                    result[i] = enumerator.Current;

                filled |= move;
            }

        if (filled)
            for (int j = i; j < count; j++)
                yield return result[j];

        for (int j = 0; j < i; j++)
            yield return result[j];

    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.