'foreach'루프에서 목록을 수정하는 가장 좋은 방법은 무엇입니까?
C # / .NET 4.0의 새로운 기능 foreach은 예외없이 에서 열거 형을 변경할 수 있다는 것 입니다. 이 변경 사항에 대한 자세한 내용은 Paul Jackson의 블로그 항목 An Interesting Side-Effect of Concurrency : Remove Items while Enumerating 을 참조하십시오.
다음을 수행하는 가장 좋은 방법은 무엇입니까?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
일반적으로 나는 IList끝날 때까지 캐시 / 버퍼로 사용 foreach하지만 더 좋은 방법이 있습니까?
foreach에서 사용되는 컬렉션은 변경할 수 없습니다. 이것은 디자인에 의한 것입니다.
MSDN에서 말했듯이 :
foreach 문은 원하는 정보를 얻기 위해 컬렉션을 반복하는 데 사용되지만 예측할 수없는 부작용을 피하기 위해 소스 컬렉션에서 항목을 추가하거나 제거하는 데 사용할 수 없습니다. 소스 컬렉션에서 항목을 추가하거나 제거해야하는 경우 for 루프를 사용합니다.
Poko가 제공 하는 링크 의 게시물은 이것이 새로운 동시 컬렉션에서 허용됨을 나타냅니다.
이 경우 IEnumerable 확장 메서드를 사용하여 열거 형의 복사본을 만들고 열거합니다. 이것은 모든 내부 열거 가능한 모든 요소의 복사본을 해당 열거에 추가합니다.
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable.ToList())
{
item.Add(item2)
}
}
언급했듯이 코드 샘플이 있습니다.
foreach(var item in collection.ToArray())
collection.Add(new Item...);
Nippysaurus의 답변을 설명하기 : 당신이하려는 경우 추가 목록에 새 항목을 같은 열거하는 동안 너무 새로 추가 된 항목을 처리하려면 다음 방금 사용 을 위해 대신 루프 foreach는 루프, 문제가 해결 :)
var list = new List<YourData>();
... populate the list ...
//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
var entryToProcess = list[i];
var resultOfProcessing = DoStuffToEntry(entryToProcess);
if (... condition ...)
list.Add(new YourData(...));
}
실행 가능한 예 :
void Main()
{
var list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(i);
//foreach (var entry in list)
for (int i = 0; i < list.Count; i++)
{
var entry = list[i];
if (entry % 2 == 0)
list.Add(entry + 1);
Console.Write(entry + ", ");
}
Console.Write(list);
}
마지막 예의 출력 :
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
목록 (15 개 항목)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
이를 수행하는 방법은 다음과 같습니다 (빠르고 더러운 솔루션. 이런 종류의 동작이 정말로 필요한 경우 디자인을 재고하거나 모든 IList<T>멤버를 재정의 하고 소스 목록을 집계해야합니다).
using System;
using System.Collections.Generic;
namespace ConsoleApplication3
{
public class ModifiableList<T> : List<T>
{
private readonly IList<T> pendingAdditions = new List<T>();
private int activeEnumerators = 0;
public ModifiableList(IEnumerable<T> collection) : base(collection)
{
}
public ModifiableList()
{
}
public new void Add(T t)
{
if(activeEnumerators == 0)
base.Add(t);
else
pendingAdditions.Add(t);
}
public new IEnumerator<T> GetEnumerator()
{
++activeEnumerators;
foreach(T t in ((IList<T>)this))
yield return t;
--activeEnumerators;
AddRange(pendingAdditions);
pendingAdditions.Clear();
}
}
class Program
{
static void Main(string[] args)
{
ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });
foreach(int i in ints)
ints.Add(i * 2);
foreach(int i in ints)
Console.WriteLine(i * 2);
}
}
}
LINQ 는 컬렉션을 다루는 데 매우 효과적입니다.
귀하의 유형과 구조는 명확하지 않지만 최선을 다해 귀하의 모범을 맞추려고 노력할 것입니다.
코드에서 각 항목에 대해 자체 'Enumerable'속성의 모든 항목을 해당 항목에 추가하는 것으로 보입니다. 이것은 매우 간단합니다.
foreach (var item in Enumerable)
{
item = item.AddRange(item.Enumerable));
}
보다 일반적인 예로, 컬렉션을 반복하고 특정 조건이 참인 항목을 제거한다고 가정 해 보겠습니다. foreachLINQ를 사용하여 방지 :
myCollection = myCollection.Where(item => item.ShouldBeKept);
각 기존 항목을 기반으로 항목을 추가 하시겠습니까? 문제 없어요:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The for loop is a nice alternative, but if your IEnumerable collection does not implement ICollection, it is not possible.
Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (@tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a List<T> and a T[] can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.
For example, suppose you have a List<string> and wish to have every string in the list which starts with T be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:
int srcPtr,destPtr;
string[] arr;
srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
string st = arr[srcPtr];
char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
if (ch != 'U')
arr[destPtr++] = st;
if (ch == 'T')
arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
theList = new List<String>(arr); // Adds extra elements
if (destPtr != arr.Length)
theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
Array.Resize(ref arr, destPtr);
theList = new List<String>(arr); // Adds extra elements
}
It would have been helpful if List<T> provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.
You should really use for() instead of foreach() in this case.
To add to Timo's answer LINQ can be used like this as well:
items = items.Select(i => {
...
//perform some logic adding / updating.
return i / return new Item();
...
//To remove an item simply have logic to return null.
//Then attach the Where to filter out nulls
return null;
...
}).Where(i => i != null);
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
{
foreach (Match match in reg.Matches(lines))
{
var aStringBuilder = new StringBuilder(lines);
aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
lines[k] = aStringBuilder.ToString();
tempReg = 0;
break;
}
}
참고URL : https://stackoverflow.com/questions/759966/what-is-the-best-way-to-modify-a-list-in-a-foreach-loop
'Nice programing' 카테고리의 다른 글
| Android Instrumentation 테스트와 Android Studio의 단위 테스트의 차이점은 무엇입니까? (0) | 2020.11.11 |
|---|---|
| Redux에서 mapStateToProps없이 DispatchToProps를 매핑 할 수 있습니까? (0) | 2020.11.11 |
| Jquery $ (this) 자식 선택기 (0) | 2020.11.11 |
| C에서 좋은 해시 테이블 구현을 찾고 (0) | 2020.11.11 |
| MEF 대 모든 IoC (0) | 2020.11.11 |