나는 foreach 내부에 루프 카운트 인덱스를 갖고 정수를 만들고, 사용하고, 증분하는 등의 프로그래밍을하는 동안이 문제를 자주 겪습니다. foreach 내부의 루프 카운트? 다른 루프에서도 사용할 수 있습니다.
컴파일러 가이 키워드를 어디서나 루프 구문에서 사용하도록 허용하지 않는지 키워드 사용에 반대합니까?
for ()
루프 를 사용하고 싶을 것입니다 .
나는 foreach 내부에 루프 카운트 인덱스를 갖고 정수를 만들고, 사용하고, 증분하는 등의 프로그래밍을하는 동안이 문제를 자주 겪습니다. foreach 내부의 루프 카운트? 다른 루프에서도 사용할 수 있습니다.
컴파일러 가이 키워드를 어디서나 루프 구문에서 사용하도록 허용하지 않는지 키워드 사용에 반대합니까?
for ()
루프 를 사용하고 싶을 것입니다 .
답변:
루프 내부에 루프 카운트가 필요한 경우 foreach
일반 for
루프를 사용하지 마십시오 . foreach
루프의 특정 사용하기 위해 의도 된 for
단순 루프를. 의 단순성 foreach
이 더 이상 도움이되지 않는 상황이있는 것처럼 들립니다 .
IEnumerable.Count
비용이 많이들 수 있습니다 (한 번만 열거하는 경우 불가능). 안전하게하기 전에 기본 소스가 무엇인지 알아야합니다.
foreach
이상 for (int i = 0…)
. 그는 몇 페이지를 작성했지만 반복에 대한 컴파일러 최적화라는 두 단어로 요약 할 수 있습니다. 좋아, 그것은 두 단어가 아니었다.
for
루프가 더 읽기 쉬운 코드를 제공 하는 이론적 인 OP와 같은 상황을 보았습니다 (이론적 컴파일러 최적화는 종종 조기 최적화입니다).
이런 익명의 유형을 사용할 수 있습니다
foreach (var item in items.Select((v, i) => new { Value = v, Index = i }))
{
Console.WriteLine("Item value is {0} and index is {1}.", item.Value, item.Index);
}
이것은 파이썬의 enumerate
기능 과 유사 합니다
for i, v in enumerate(items):
print v, i
요청에 따라 Dan Finch의 답변을 여기에 추가하고 있습니다.
나에게 포인트를주지 말고 Dan Finch에게 포인트를주십시오 :-)
해결책은 다음과 같은 일반적인 확장 방법을 작성하는 것입니다.
public static void Each<T>( this IEnumerable<T> ie, Action<T, int> action )
{
var i = 0;
foreach ( var e in ie ) action( e, i++ );
}
다음과 같이 사용됩니다.
var strings = new List<string>();
strings.Each( ( str, n ) =>
{
// hooray
} );
나는 이것에 대해 틀릴 수도 있지만, 항상 foreach 루프의 핵심은 C ++의 STL 시절부터 반복을 단순화하는 것이라고 생각했습니다.
for(std::stltype<typename>::iterator iter = stl_type_instance.begin(); iter != stl_type_instance.end(); iter++)
{
//dereference iter to use each object.
}
이것을 foreach에서 .NET의 IEnumerable 사용과 비교하십시오.
foreach(TypeName instance in DescendentOfIEnumerable)
{
//use instance to use the object.
}
후자는 훨씬 간단하고 많은 오래된 함정을 피합니다. 또한 그들은 거의 동일한 규칙을 따르는 것 같습니다. 예를 들어 루프 내부에서 IEnumerable 내용을 변경할 수 없습니다 (STL 방식으로 생각하면 훨씬 더 의미가 있습니다). 그러나 for 루프는 종종 반복과 다른 논리적 목적을 가지고 있습니다.
for(IEnumerator e=collection.GetEnumerator;e.MoveNext();) { ... }
해당 컬렉션이 인 경우 인덱싱과 함께 IList<T>
간단히 사용할 수 있습니다 for
.
for (int i = 0; i < collection.Count; i++)
{
var item = collection[i];
// …
}
그렇지 않은 경우을 사용할 Select()
수 있으며 인덱스를 제공하는 과부하가 있습니다.
그것이 적절하지 않다면 수동으로 색인을 유지하는 것이 간단하다고 생각합니다. 두 줄의 코드입니다. 이를 위해 특별히 키워드를 작성하는 것은 과도한 일입니다.
int i = 0;
foreach (var item in collection)
{
// …
i++;
}
foo(++i)
또는 foo(i++)
인덱스가 필요에 따라합니다.
컬렉션이 IEnumerable이라는 것을 알고 있지만 지금까지 처리 한 요소 수 (따라서 완료된 총계)를 추적해야하는 경우 기본 for 루프에 몇 줄을 추가 할 수 있습니다.
var coll = GetMyCollectionAsAnIEnumerable();
var idx = 0;
for(var e = coll.GetEnumerator(); e.MoveNext(); idx++)
{
var elem = e.Current;
//use elem and idx as you please
}
foreach에 증가 된 색인 변수를 추가 할 수도 있습니다.
var i=0;
foreach(var elem in coll)
{
//do your thing, then...
i++;
}
보다 우아하게 보이게하려면 다음 방법을 정의하여 다음 세부 사항을 "숨길"수 있습니다.
public static void ForEach<T>(this IEnumerable<T> input, Action<T> action)
{
foreach(T elem in input)
action(elem);
}
public static void ForEach<T>(this IEnumerable<T> input, Action<T, int> action)
{
var idx = 0;
foreach(T elem in input)
action(elem, idx++); //post-increment happens after parameter-passing
}
//usage of the index-supporting method
coll.ForEach((e, i)=>Console.WriteLine("Element " + (i+1) + ": " + e.ToString()));