C#에서 반복하는 동안 열거 가능한 컬렉션에서 항목을 수정하거나 삭제하는 방법
-
08-07-2019 - |
문제
데이터 테이블에서 일부 행을 삭제해야합니다. 컬렉션을 반복하면서 컬렉션을 변경하는 것이 좋지 않다고 들었습니다. 따라서 행이 삭제 요구를 충족 한 다음 삭제 된 것으로 표시하는 루프 대신에 먼저 데이터 테이블을 반복하고 목록에 모든 행을 추가 한 다음 목록 및 마크를 반복해야합니다. 삭제 행. 이에 대한 이유는 무엇이며 어떤 대안이 있는가 (줄 목록을 사용하는 대신)?.
해결책
간단한 것을 사용하는 경우 컬렉션에서 요소를 제거 할 수 있습니다. for
고리.
이 예를 살펴보십시오.
var l = new List<int>();
l.Add(0);
l.Add(1);
l.Add(2);
l.Add(3);
l.Add(4);
l.Add(5);
l.Add(6);
for (int i = 0; i < l.Count; i++)
{
if (l[i] % 2 == 0)
{
l.RemoveAt(i);
i--;
}
}
foreach (var i in l)
{
Console.WriteLine(i);
}
다른 팁
요소와 다른 요소를 제거하면 "간격에 빠지는"요소를 제거하면 이미 조사했기 때문에 중요하지 않기 때문에 목록을 통해 뒤로 반복하는 것은 더 나은 접근 방식처럼 들립니다. 또한 카운터 변수가 .count보다 커지는 것에 대해 걱정할 필요가 없습니다.
List<int> test = new List<int>();
test.Add(1);
test.Add(2);
test.Add(3);
test.Add(4);
test.Add(5);
test.Add(6);
test.Add(7);
test.Add(8);
for (int i = test.Count-1; i > -1; i--)
{
if(someCondition){
test.RemoveAt(i);
}
}
@bruno 코드를 복용하면 거꾸로 할 것입니다.
뒤로 이동하면 누락 된 배열 지수는 루프 순서를 방해하지 않습니다.
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
for (int i = l.Count - 1; i >= 0; i--)
if (l[i] % 2 == 0)
l.RemoveAt(i);
foreach (var i in l)
{
Console.WriteLine(i);
}
그러나 요즘에는 linq를 사용할 것입니다.
var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 });
l.RemoveAll(n => n % 2 == 0);
DataTable으로 작업하고 테이블 어댑터를 사용하여 서버로 다시 변경할 수 있어야하므로 (주석 참조) 행을 삭제 해야하는 방법의 예는 다음과 같습니다.
DataTable dt;
// remove all rows where the last name starts with "B"
foreach (DataRow row in dt.Rows)
{
if (row["LASTNAME"].ToString().StartsWith("B"))
{
// mark the row for deletion:
row.Delete();
}
}
행에서 삭제를 호출하면 Rowstate 속성이 삭제되도록 변경되지만 삭제 된 행을 테이블에 두십시오. 서버로 다시 변경하기 전에이 테이블을 사용해야하는 경우 (테이블의 내용을 삭제 된 행을 뺀 테이블의 내용을 표시하려면) 각 행의 행 상태를 확인해야합니다. :
foreach (DataRow row in dt.Rows)
{
if (row.RowState != DataRowState.Deleted)
{
// this row has not been deleted - go ahead and show it
}
}
컬렉션에서 행을 제거하면 (Bruno의 답변에서와 같이) 테이블 어댑터가 나오며 일반적으로 데이터 가능성으로 수행되지 않아야합니다.
While Loop은 다음을 처리합니다.
int i = 0;
while(i < list.Count)
{
if(<codition for removing element met>)
{
list.RemoveAt(i);
}
else
{
i++;
}
}
Lambda 표현보다는 대의원을 사용하여 .NET 2.0 (LINQ/LAMDA 표현식 없음)을 목표로하는 경우 Chakrit의 솔루션을 사용할 수 있습니다.
public bool IsMatch(int item) {
return (item % 3 == 1); // put whatever condition you want here
}
public void RemoveMatching() {
List<int> x = new List<int>();
x.RemoveAll(new Predicate<int>(IsMatch));
}
목록을 반복하는 동안 목록을 삭제하거나 추가하면 말한 것처럼 파손될 수 있습니다.
나는 종종 문제를 해결하기 위해 두 개의 목록 접근법을 사용했습니다.
ArrayList matches = new ArrayList(); //second list
for MyObject obj in my_list
{
if (obj.property == value_i_care_about)
matches.addLast(obj);
}
//now modify
for MyObject m in matches
{
my_list.remove(m); //use second list to delete from first list
}
//finished.
열거하는 컬렉션에서 항목을 제거해야 할 때는 보통 반대로 열거됩니다.