programing

LINQ를 사용하여 리스트에서 요소 제거

subpage 2023. 4. 14. 21:42
반응형

LINQ를 사용하여 리스트에서 요소 제거

다음과 같은 LINQ 쿼리가 있다고 가정합니다.

var authors = from x in authorsList
              where x.firstname == "Bob"
              select x;

그 때문에authorsList종류List<Author>, 을 삭제하려면 어떻게 해야 합니다.Author의 요소authorsList에 대한 쿼리에 의해 반환되는authors?

다른 말로 하자면, 어떻게 하면 밥과 같은 이름의 모든 것을 삭제할 수 있을까?authorsList?

참고: 이것은 질문의 목적을 위한 간단한 예시입니다.

글쎄요, 첫 번째 장소에서 제외하기 쉽도록 하겠습니다.

authorsList = authorsList.Where(x => x.FirstName != "Bob").ToList();

그러나 그것은 단지 가치 변화를 바꿀 것이다.authorsList이전 컬렉션에서 작성자를 삭제하는 대신.또는 다음을 사용할 수 있습니다.

authorsList.RemoveAll(x => x.FirstName == "Bob");

다른 수집에 기반해야 할 경우 해시 세트를 사용하여 해시 세트를 제거하고 다음을 포함합니다.

var setToRemove = new HashSet<Author>(authors);
authorsList.RemoveAll(x => setToRemove.Contains(x));

목록<T를 사용하려면 좋습니다.T>이것을 성취하기 위해 모든 것을 제거합니다.

authorsList.RemoveAll((x) => x.firstname == "Bob");

꼭 아이템을 삭제해야 한다면 Except()는 어떻습니까?
새 목록을 기준으로 제거하거나 Linq를 중첩하여 즉시 제거할 수 있습니다.

var authorsList = new List<Author>()
{
    new Author{ Firstname = "Bob", Lastname = "Smith" },
    new Author{ Firstname = "Fred", Lastname = "Jones" },
    new Author{ Firstname = "Brian", Lastname = "Brains" },
    new Author{ Firstname = "Billy", Lastname = "TheKid" }
};

var authors = authorsList.Where(a => a.Firstname == "Bob");
authorsList = authorsList.Except(authors).ToList();
authorsList = authorsList.Except(authorsList.Where(a=>a.Firstname=="Billy")).ToList();

LINQ는 업데이트 지원이 아닌 쿼리를 제공하기 때문에 표준 LINQ 연산자에서는 이 작업을 수행할 수 없습니다.

그러나 새 목록을 생성하여 이전 목록을 대체할 수 있습니다.

var authorsList = GetAuthorList();

authorsList = authorsList.Where(a => a.FirstName != "Bob").ToList();

또는 의 모든 항목을 제거할 수 있습니다.authors두 번째 패스로

var authorsList = GetAuthorList();

var authors = authorsList.Where(a => a.FirstName == "Bob").ToList();

foreach (var author in authors)
{
    authorList.Remove(author);
}

심플한 솔루션:

static void Main()
{
    List<string> myList = new List<string> { "Jason", "Bob", "Frank", "Bob" };
    myList.RemoveAll(x => x == "Bob");

    foreach (string s in myList)
    {
        //
    }
}

궁금해서 그러는데, 혹시 이 두 가지 차이점이 있을까?RemoveAll그리고.Except및 사용의 장점HashSet퀵 퍼포먼스 체크를 했습니다:)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace ListRemoveTest
{
    class Program
    {
        private static Random random = new Random( (int)DateTime.Now.Ticks );

        static void Main( string[] args )
        {
            Console.WriteLine( "Be patient, generating data..." );

            List<string> list = new List<string>();
            List<string> toRemove = new List<string>();
            for( int x=0; x < 1000000; x++ )
            {
                string randString = RandomString( random.Next( 100 ) );
                list.Add( randString );
                if( random.Next( 1000 ) == 0 )
                    toRemove.Insert( 0, randString );
            }

            List<string> l1 = new List<string>( list );
            List<string> l2 = new List<string>( list );
            List<string> l3 = new List<string>( list );
            List<string> l4 = new List<string>( list );

            Console.WriteLine( "Be patient, testing..." );

            Stopwatch sw1 = Stopwatch.StartNew();
            l1.RemoveAll( toRemove.Contains );
            sw1.Stop();

            Stopwatch sw2 = Stopwatch.StartNew();
            l2.RemoveAll( new HashSet<string>( toRemove ).Contains );
            sw2.Stop();

            Stopwatch sw3 = Stopwatch.StartNew();
            l3 = l3.Except( toRemove ).ToList();
            sw3.Stop();

            Stopwatch sw4 = Stopwatch.StartNew();
            l4 = l4.Except( new HashSet<string>( toRemove ) ).ToList();
            sw3.Stop();


            Console.WriteLine( "L1.Len = {0}, Time taken: {1}ms", l1.Count, sw1.Elapsed.TotalMilliseconds );
            Console.WriteLine( "L2.Len = {0}, Time taken: {1}ms", l1.Count, sw2.Elapsed.TotalMilliseconds );
            Console.WriteLine( "L3.Len = {0}, Time taken: {1}ms", l1.Count, sw3.Elapsed.TotalMilliseconds );
            Console.WriteLine( "L4.Len = {0}, Time taken: {1}ms", l1.Count, sw3.Elapsed.TotalMilliseconds );

            Console.ReadKey();
        }


        private static string RandomString( int size )
        {
            StringBuilder builder = new StringBuilder();
            char ch;
            for( int i = 0; i < size; i++ )
            {
                ch = Convert.ToChar( Convert.ToInt32( Math.Floor( 26 * random.NextDouble() + 65 ) ) );
                builder.Append( ch );
            }

            return builder.ToString();
        }
    }
}

결과는 다음과 같습니다.

Be patient, generating data...
Be patient, testing...
L1.Len = 985263, Time taken: 13411.8648ms
L2.Len = 985263, Time taken: 76.4042ms
L3.Len = 985263, Time taken: 340.6933ms
L4.Len = 985263, Time taken: 340.6933ms

보다시피, 이 경우 최선의 방법은

이것은 매우 오래된 질문입니다만, 매우 간단한 방법을 찾았습니다.

authorsList = authorsList.Except(authors).ToList();

반환 변수 때문에authorsList는 입니다.List<T>,그IEnumerable<T>에 의해 반환되었다Except()로 변환해야 합니다.List<T>.

두 가지 방법으로 제거할 수 있습니다.

var output = from x in authorsList
             where x.firstname != "Bob"
             select x;

또는

var authors = from x in authorsList
              where x.firstname == "Bob"
              select x;

var output = from x in authorsList
             where !authors.Contains(x) 
             select x;

저도 같은 문제가 있었습니다만, where 조건에 근거해 심플한 출력을 원한다면, 첫 번째 솔루션이 더 좋습니다.

그렇게 말해라authorsToRemove는 입니다.IEnumerable<T>삭제할 요소가 포함되어 있습니다.authorsList.

다음으로 OP가 요구하는 제거 작업을 수행하는 간단한 방법을 제시하겠습니다.

authorsList.RemoveAll(authorsToRemove.Contains);

목록에서 요소를 삭제하는 예를 다음에 나타냅니다.

 List<int> items = new List<int>() { 2, 2, 3, 4, 2, 7, 3,3,3};

 var result = items.Remove(2);//Remove the first ocurence of matched elements and returns boolean value
 var result1 = items.RemoveAll(lst => lst == 3);// Remove all the matched elements and returns count of removed element
 items.RemoveAt(3);//Removes the elements at the specified index

LINQ는 객체의 불변성을 강조하는 기능적 프로그래밍에 기원을 두고 있기 때문에 원래 목록을 새로 고치는 기본 제공 방법을 제공하지 않습니다.

불변성에 관한 주의사항(다른 SO 답변에서 인용):

여기 위키피디아에서 말하는 불변의 정의가 있습니다.

객체 지향 및 기능 프로그래밍에서 불변 객체는 생성된 후 상태를 수정할 수 없는 객체입니다.

이런 것도 할 수 있을 것 같은데

    authorsList = (from a in authorsList
                  where !authors.Contains(a)
                  select a).ToList();

저는 이미 주어진 해결책들이 문제를 더 읽기 쉽게 해결한다고 생각합니다.

작성자 목록에 있는 항목을 새 목록에 할당하기만 하면 효과를 볼 수 있습니다.

//assume oldAuthor is the old list
Author newAuthorList = (select x from oldAuthor where x.firstname!="Bob" select x).ToList();
oldAuthor = newAuthorList;
newAuthorList = null;

코드를 유연하게 유지하려면(코드 최적화가 중요하지 않은 경우) 목록에서 추가 작업을 수행해야 합니다.

authorsList = authorsList.Where(x => x.FirstName != "Bob").<do_some_further_Linq>;

또는

authorsList = authorsList.Where(x => !setToRemove.Contains(x)).<do_some_further_Linq>;

언급URL : https://stackoverflow.com/questions/853526/using-linq-to-remove-elements-from-a-listt

반응형