foreach를 통해 뒤로 반복 할 수 있습니까? 하고 동일한 효과를

for문을 사용 하고 동일한 효과를 얻을 수 있다는 것을 알고 있지만 foreachC # 의 루프를 통해 뒤로 루프 할 수 있습니까?



답변

목록 작업 (직접 인덱싱)시 for루프 를 사용하는 것만 큼 효율적으로 수행 할 수 없습니다 .

편집 : 일반적으로 루프 를 사용할 수있을for 때이 작업에 대한 올바른 방법 일 수 있습니다. 또한, foreach순서대로 구현되는 한, 구조 자체는 요소 인덱스 및 반복 순서와 무관 한 루프를 표현하기 위해 빌드되며, 이는 병렬 프로그래밍 에서 특히 중요 합니다 . 이다 내 의견으로 반복 사용하지 말아야 순서에 의존하는 것을 foreach반복합니다.


답변

.NET 3.5를 사용하는 경우 다음을 수행 할 수 있습니다.

IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())

기본적으로 열거자를 통해 모든 것을 스택에 넣은 다음 모든 것을 역순으로 팝해야하므로 매우 효율적이지 않습니다.

직접 색인 가능한 컬렉션 (예 : IList)이있는 경우 반드시 for 루프를 .

.NET 2.0에 있고 for 루프를 사용할 수없는 경우 (즉, IEnumerable 만있는 경우) 자신 만의 Reverse 함수를 작성하면됩니다. 이것은 작동해야합니다 :

static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
    return new Stack<T>(input);
}

이것은 아마도 그다지 명백하지 않은 행동에 의존합니다. IEnumerable을 스택 생성자에 전달하면 해당 항목을 반복하고 항목을 스택으로 푸시합니다. 그런 다음 스택을 반복하면 물건이 역순으로 튀어 나옵니다.

이 항목과 .NET 3.5 Reverse()확장 방법은 항목 반환을 멈추지 않는 IEnumerable을 공급하면 분명히 폭발 할 것입니다.


답변

280Z28에서 IList<T>알 수 있듯이 인덱스를 사용할 수 있습니다. 확장 방법으로 이것을 숨길 수 있습니다.

public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
    for (int i = items.Count-1; i >= 0; i--)
    {
        yield return items[i];
    }
}

이것은 Enumerable.Reverse()모든 데이터를 먼저 버퍼링하는 것보다 빠릅니다 . ( Reverse이러한 방식으로 최적화가 적용 되지 않았다고 생각 합니다 Count().)이 버퍼링은 처음 반복을 시작할 때 데이터를 완전히 읽은 것을 의미하지만 FastReverse반복하는 동안 목록의 변경 사항을 “볼”것입니다. (반복 사이에 여러 항목을 제거하면 손상됩니다.)

일반적인 시퀀스의 경우 역순으로 반복하는 방법이 없습니다. 예를 들어 시퀀스는 무한 할 수 있습니다.

public static IEnumerable<T> GetStringsOfIncreasingSize()
{
    string ret = "";
    while (true)
    {
        yield return ret;
        ret = ret + "x";
    }
}

반대로 반복하려고하면 어떻게 될까요?


답변

foreach반복에 사용하기 전에 다음 reverse방법으로 목록을 반대로하십시오 .

    myList.Reverse();
    foreach( List listItem in myList)
    {
       Console.WriteLine(listItem);
    }


답변

때로는 고급 색인 생성 기능이 없거나 Linq 쿼리 결과를 반대로 바꾸거나 소스 컬렉션을 수정하고 싶지 않은 경우 Linq가 도움이 될 수 있습니다.

Linq에 익명 형식을 사용하는 Linq 확장 방법 Linq OrderByDescending에 대한 정렬 키를 제공하려면 선택하십시오.

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

용법:

    var eable = new[]{ "a", "b", "c" };

    foreach(var o in eable.Invert())
    {
        Console.WriteLine(o);
    }

    // "c", "b", "a"

“Reverse”와 동의어이고 List Reverse 구현과 명확성을 가지기 때문에 “Invert”로 명명됩니다.

Int32.MinValue 및 Int32.MaxValue가 모든 종류의 컬렉션 인덱스 범위를 벗어나므로 컬렉션의 특정 범위를 되돌릴 수도 있습니다.이를 주문 프로세스에 활용할 수 있습니다. 요소 인덱스가 지정된 범위 아래에있는 경우 OrderByDescending을 사용할 때 순서가 변경되지 않도록 Int32.MaxValue가 지정됩니다. 마찬가지로 지정된 범위보다 큰 인덱스의 요소에 Int32.MinValue가 지정됩니다. 주문 프로세스의 끝에 나타납니다. 지정된 범위 내의 모든 요소에는 일반 인덱스가 할당되고 그에 따라 반대로됩니다.

    public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count)
    {
        var transform = source.Select(
            (o, i) => new
            {
                Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i,
                Object = o
            });

        return transform.OrderByDescending(o => o.Index)
                        .Select(o => o.Object);
    }

용법:

    var eable = new[]{ "a", "b", "c", "d" };

    foreach(var o in eable.Invert(1, 2))
    {
        Console.WriteLine(o);
    }

    // "a", "c", "b", "d"

Linq 구현의 성능 적중과 임시 List를 사용하여 역전을 위해 컬렉션을 래핑하는 것에 대해서는 확신하지 않습니다.


글을 쓰는 시점에서 Linq의 Reverse 구현을 알지 못했지만 여전히이 작업을 수행하는 것이 재미있었습니다.
https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx


답변

List <T>를 사용하는 경우이 코드를 사용할 수도 있습니다.

List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();

목록 자체를 반대로 쓰는 방법입니다.

이제 foreach :

foreach(string s in list)
{
    Console.WriteLine(s);
}

출력은 다음과 같습니다.

3
2
1


답변

그것은이다 당신이 컬렉션 코드를 변경할 수있는 경우에 가능 구현을 IEnumerable 또는 IEnumerable을가 (IList의 당신 자신의 구현을 예) 있음을.

예를 들어 IEnumerable 인터페이스를 통한 다음 구현과 같이이 작업을 수행 하는 반복자를 작성하십시오 ( ‘items’가이 샘플의 목록 필드라고 가정).

public IEnumerator<TObject> GetEnumerator()
{
    for (var i = items.Count - 1; i >= 0; i--)
    {
        yield return items[i];
    }
}

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

이 때문에 목록은 목록을 거꾸로 반복합니다.

힌트 : 당신은 문서 내에서 목록 의이 특별한 행동을 명확하게 진술해야합니다 (스택 또는 대기열과 같은 자체 설명 클래스 이름을 선택하는 것이 더 좋습니다).