[C#] LINQ를 사용하여 List <T>에서 요소 제거

다음과 같은 LINQ 쿼리가 있다고 가정하십시오.

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

그것이 authorsList유형 이라면, 쿼리에 의해 반환 된 요소를 List<Author>어떻게 삭제할 수 있습니까?AuthorauthorsListauthors

또는 다른 방법으로, 이름의 동일한 Bob을 모두에서 어떻게 삭제할 수 authorsList있습니까?

참고 : 이것은 질문의 목적을 위해 단순화 된 예입니다.



답변

글쎄, 처음에 그것들을 배제하는 것이 더 쉬울 것입니다 :

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

그러나 authorsList이전 컬렉션에서 작성자를 제거하는 대신 값을 변경하면 됩니다. 또는 다음을 사용할 수 있습니다 RemoveAll.

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

다른 컬렉션을 기반으로 해야하는 경우 HashSet, RemoveAll 및 Contains를 사용합니다.

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


답변

이를 위해서는 List <T> .RemoveAll 을 사용하는 것이 좋습니다 .

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

우리가 볼 수 있듯이, 그 경우 가장 좋은 옵션은 RemoveAll(HashSet)


답변

이것은 매우 오래된 질문이지만이 작업을 수행하는 간단한 방법을 찾았습니다.

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

반환 변수 authorsList는 a List<T>이므로로 IEnumerable<T>반환되는 변수 는 Except()로 변환되어야합니다 List<T>.