একটি তালিকা <টি> থেকে উপাদানগুলি সরাতে লিনকিউ ব্যবহার করা


654

বলুন যে আমার কাছে লিনকিউ ক্যোয়ারী রয়েছে যেমন:

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

প্রদত্ত যে authorsListধরনের হয় List<Author>, আমি কিভাবে মুছে ফেলতে পারেন Authorউপাদান থেকে authorsListযে মধ্যে ক্যোয়ারী দ্বারা ফিরে করছে authors?

বা, অন্য কোনও উপায়ে বলা যায়, আমি কীভাবে প্রথম নামটির সমতুল্য ববকে মুছতে পারি authorsList?

দ্রষ্টব্য: প্রশ্নের উদ্দেশ্যগুলির জন্য এটি একটি সরল উদাহরণ।

উত্তর:


1138

ঠিক আছে, এগুলিকে প্রথমে বাদ দেওয়া সহজ হবে:

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

যাইহোক, এটি কেবল authorsListপূর্ববর্তী সংগ্রহ থেকে লেখকদের অপসারণের পরিবর্তে এর মান পরিবর্তন করবে । বিকল্পভাবে, আপনি ব্যবহার করতে পারেন RemoveAll:

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

অন্য সংগ্রহের ভিত্তিতে যদি আপনার সত্যিই এটি করা দরকার হয় তবে আমি একটি হ্যাশসেট, রিমুভাল এবং কন্টেনস ব্যবহার করব:

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

14
অন্য সংগ্রহের জন্য হ্যাশসেট ব্যবহার করার কারণ কী?
123 456 789 0

54
@ লিওলুইস: এটি Containsচেকটি দ্রুত করে তোলে এবং এটি নিশ্চিত করে যে আপনি কেবল একবারের ক্রমটি মূল্যায়ন করেছেন।
জন স্কিটি

2
@ লিওলুইস: হ্যাঁ, একটি ক্রম থেকে একটি হ্যাশসেট তৈরি করা কেবল একবার এটির মূল্যায়ন করে। "দুর্বল সংগ্রহ সেট" বলতে কী বোঝায় তা নিশ্চিত নন।
জন স্কিটি

2
@ অ্যান্ড্রিচ্রিস্টোফারঅ্যান্ডারসন: "পুরানো" বলতে কী বোঝ? এটি এখনও কাজ করে। যদি আপনি একটি পেয়ে থাকেন তবে List<T>এটি ব্যবহার করা ভাল।
জন স্কিটি

4
@ অ্যান্ড্রিচ্রিস্টোফারঅ্যান্ডারসন: এটি ব্যবহার করা ভাল হবেauthorsList = authorsList.Where(x => x.FirstName != "Bob")
জন স্কিটি

133

<T> তালিকাটি ব্যবহার করা আরও ভাল । এটি সম্পন্ন করার জন্য সমস্ত সরান

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

8
@ রিড কোপসি: আপনার উদাহরণের ল্যাম্বডা প্যারামিটার বন্ধনীতে আবদ্ধ, অর্থাৎ (এক্স)। এর কি কারিগরি কারণ আছে? এটা কি ভাল অনুশীলন হিসাবে বিবেচনা করা হয়?
ম্যাট ডেভিস

24
নং> 1 পরামিতি সহ এটি প্রয়োজনীয়। একটি একক প্যারামিটার সহ এটি optionচ্ছিক তবে এটি ধারাবাহিকতা রাখতে সহায়তা করে।
রিড কোপসি

48

আপনার যদি সত্যিই আইটেমগুলি সরানোর প্রয়োজন হয় তবে () বাদে আর কী হবে?
আপনি একটি নতুন তালিকার উপর ভিত্তি করে অপসারণ করতে পারেন, বা লিনক বাসা বেঁধে অন-ফ্লাই সরিয়ে ফেলতে পারেন।

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();

Except()লিনকিউ-বিবৃতিতে যাওয়ার একমাত্র উপায়। IEnumerableনেই Remove()কিংবা RemoveAll()
জারি তুর্কিয়া

29

আপনি স্ট্যান্ডার্ড লিনকিউ অপারেটরদের সাথে এটি করতে পারবেন না কারণ লিনকুই কোয়েরি সরবরাহ করে, আপডেট সমর্থন করে না।

তবে আপনি একটি নতুন তালিকা তৈরি করতে পারেন এবং পুরানোটিকে প্রতিস্থাপন করতে পারেন।

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);
}

12
RemoveAll()লিনকিউ অপারেটর নয়।
ড্যানিয়েল ব্রুকনার

আমার ক্ষমা। আপনি 100% সঠিক। দুর্ভাগ্যক্রমে, আমি আমার ডাউনটাতে বিপরীত বলে মনে করতে পারি না। এর জন্যে দুঃখিত.
শাই কোহেন

Removeএকটি হল List< T> পদ্ধতি, না একটি System.Linq.Enumerable পদ্ধতি।
ডেভিডআরআর

@ ড্যানিয়েল, আমি ভুল হলে আমাকে সংশোধন করুন আমরা এড়াতে পারি অর্থাৎ কোডের নীচে কাজ করবে। var authorsList = getAuthorList (); var লেখক = লেখক তালিকা.এখানে (a => a.FirstName == "বব"); foreach (লেখকগুলিতে var লেখক) {লেখকলিস্ট। সরান (লেখক); }
সাঁই

হ্যাঁ, এটি কাজ করবে। এটিকে তালিকায় রূপান্তর করা কেবলমাত্র যদি আপনার কোনও তালিকায় পাস করার জন্য কোনও তালিকার দরকার হয় তবে আপনি যদি পরে আরও জিনিস যুক্ত করতে বা সরাতে চান। এটি আপনাকে যদি একাধিকবার ক্রমটি গুণতে হয় তবে এটি কার্যকরও হতে পারে কারণ তখন আপনাকে কেবল সম্ভাব্য ব্যয়বহুল মূল্যায়ন করতে হবে যেখানে শর্তটি একবার হয় বা যদি ফলাফল দুটি গণনার মধ্যে পরিবর্তিত হতে পারে, উদাহরণস্বরূপ কারণ শর্তটি বর্তমান সময়ের উপর নির্ভর করে। আপনি যদি এটি কেবল একটি লুপে ব্যবহার করতে চান তবে প্রথমে ফলাফলকে তালিকায় সংরক্ষণ করার একেবারেই দরকার নেই।
ড্যানিয়েল ব্রুকনার

20

সহজ সমাধান:

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

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

স্ট্রিং তালিকার একাধিক অর্থ "বব" এবং "জেসন" কীভাবে সরাবেন?
নিও

19

আমি ভাবছিলাম, যদি 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)


এই কোড: "l2.RemoveAll (নতুন হ্যাশসেট <স্ট্রিং> (toRemove)। কনটেনস);" সংকলন করা উচিত নয় ... এবং যদি আপনার পরীক্ষাগুলি সঠিক হয় তবে তারা জোন স্কিট ইতিমধ্যে যে পরামর্শ দিয়েছিল তার চেয়ে দ্বিগুণ।
পাস্কাল

2
l2.RemoveAll( new HashSet<string>( toRemove ).Contains );
জরিমানাটি

9

এটি একটি খুব পুরানো প্রশ্ন, তবে আমি এটি করার জন্য একটি খুব সহজ উপায় পেয়েছি:

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

নোট করুন যেহেতু রিটার্ন ভেরিয়েবল authorsLista List<T>, তাই IEnumerable<T>প্রত্যাবর্তিত Except()অবশ্যই A তে রূপান্তর করতে হবে List<T>


7

আপনি দুটি উপায়ে অপসারণ করতে পারেন

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;

আমার একই সমস্যা ছিল, আপনি যদি আপনার অবস্থার উপর ভিত্তি করে সাধারণ আউটপুট চান তবে প্রথম সমাধানটি আরও ভাল।


আমি কীভাবে "বব" বা "বিলি" যাচাই করতে পারি?
Si8

6

বলুন এটি authorsToRemoveএমন একটি IEnumerable<T>যা আপনি যে উপাদানগুলি থেকে মুছতে চান তা রয়েছে authorsList

তারপরে ওপি কর্তৃক জিজ্ঞাসা করা অপসারণ কার্য সম্পাদনের জন্য এখানে আরও একটি সহজ উপায়:

authorsList.RemoveAll(authorsToRemove.Contains);

5

আমি মনে করি আপনি এই জাতীয় কিছু করতে পারেন

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

যদিও আমি মনে করি ইতিমধ্যে প্রদত্ত সমাধানগুলি আরও পাঠযোগ্য উপায়ে সমস্যার সমাধান করে।


4

নীচে তালিকা থেকে উপাদান অপসারণ উদাহরণ।

 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

1

লিনকিউ এর উত্স ফাংশনাল প্রোগ্রামিংয়ে রয়েছে, যা বস্তুর অপরিবর্তনীয়তার উপর জোর দেয়, তাই এটি স্থানটিতে মূল তালিকাটি আপডেট করার জন্য অন্তর্নির্মিত উপায় সরবরাহ করে না।

অপরিবর্তনীয়তা সম্পর্কে নোট (অন্য এসও উত্তর থেকে নেওয়া):

উইকিপিডিয়া থেকে অপরিবর্তনীয়তার সংজ্ঞা এখানে দেওয়া হল ।

অবজেক্ট-ওরিয়েন্টেড এবং ফাংশনাল প্রোগ্রামিংয়ে, একটি অপরিবর্তনীয় অবজেক্ট হ'ল একটি অবজেক্ট যা এর অবস্থা তৈরির পরে তার রাজ্যটি পরিবর্তন করা যায় না।


0

আমি মনে করি আপনাকে প্রভাবিত করতে আপনাকে কেবল লেখকের তালিকা থেকে একটি নতুন তালিকায় আইটেমগুলি নির্ধারণ করতে হবে।

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

0

কোড সাবলীল রাখতে (যদি কোড অপ্টিমাইজেশন গুরুতর না হয়) এবং আপনাকে তালিকায় আরও কিছু পরিচালনা করতে হবে:

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

অথবা

authorsList = authorsList.Where(x => !setToRemove.Contains(x)).<do_some_further_Linq>;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.