C#에서 반복하는 동안 열거 가능한 컬렉션에서 항목을 수정하거나 삭제하는 방법

StackOverflow https://stackoverflow.com/questions/308466

  •  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.

열거하는 컬렉션에서 항목을 제거해야 할 때는 보통 반대로 열거됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top