C # में फ़िल्टरिंग संग्रह


142

मैं C # में एक संग्रह को फ़िल्टर करने के लिए एक बहुत तेज़ तरीके की तलाश कर रहा हूं। मैं वर्तमान में सामान्य सूची <ऑब्जेक्ट> संग्रह का उपयोग कर रहा हूं, लेकिन यदि वे बेहतर प्रदर्शन करते हैं तो अन्य संरचनाओं का उपयोग करने के लिए खुले हैं।

वर्तमान में, मैं सिर्फ एक नई सूची बना रहा हूं <ऑब्जेक्ट> और मूल सूची के माध्यम से लूपिंग। यदि फ़िल्टरिंग मानदंड मेल खाते हैं, तो मैं नई सूची में एक कॉपी डाल देता हूं।

क्या ऐसा करने के लिए इससे अच्छा तरीका है? क्या जगह को छानने का कोई तरीका है ताकि कोई अस्थायी सूची आवश्यक न हो?


जो धधकते हुए तेजी से निकल रहा है। क्या यह आपके सिस्टम को धीमा कर रहा है? एक विशाल सूची है? अन्यथा, मैं चिंता नहीं करता।
होल्डर

जवाबों:


237

यदि आप C # 3.0 का उपयोग कर रहे हैं, तो आप linq का उपयोग कर सकते हैं, बेहतर तरीके से और अधिक सुरुचिपूर्ण तरीके से:

List<int> myList = GetListOfIntsFromSomewhere();

// This will filter out the list of ints that are > than 7, Where returns an
// IEnumerable<T> so a call to ToList is required to convert back to a List<T>.
List<int> filteredList = myList.Where( x => x > 7).ToList();

यदि आप नहीं ढूंढ सकते हैं .Where, तो इसका मतलब है कि आपको using System.Linq;अपनी फ़ाइल के शीर्ष पर आयात करने की आवश्यकता है ।


19
जहां एक्सटेंशन विधि IEnumerable <T> देता है, सूची <T> नहीं। यह होना चाहिए: myList.Where (x => x> 7) .TLList ()
राफा

1
स्ट्रिंग्स द्वारा फ़िल्टरिंग के लिए यह कैसे काम करता है। स्ट्रिंग्स की एक सूची में सभी वस्तुओं को खोजने की तरह जो "ch" से शुरू होती है
जोंकोडो

2
@ जोनाथनो आप फंक के अंदर के तरीकों का उपयोग कर सकते हैं। listOfStrings.Where (s => s.StartsWith ("ch"))। ToList ();
माइक जी

1
क्या लिनेक प्रश्नों पर आपत्ति जताने का कोई तरीका है? उदाहरण के लिए, उपयोग .Where(predefinedQuery)करने के बजाय उपयोग करने के लिए .Where(x => x > 7)?
XenoRo

2
@AlmightyR: बस इसे एक विधि के रूप में परिभाषित करें जो एक तर्क लेता है। उदाहरण के लिए: public bool predefinedQuery(int x) { return x > 7; }। तब आपका .Where(predefinedQuery)काम ठीक होता।
डॉन

21

यहां तीन अलग-अलग तरीकों का उपयोग करके कुछ सूची फ़िल्टरिंग का एक कोड ब्लॉक / उदाहरण दिया गया है जो मैंने लैम्ब्डा और LINQ आधारित सूची को फ़िल्टर करने के लिए एक साथ रखा है।

#region List Filtering

static void Main(string[] args)
{
    ListFiltering();
    Console.ReadLine();
}

private static void ListFiltering()
{
    var PersonList = new List<Person>();

    PersonList.Add(new Person() { Age = 23, Name = "Jon", Gender = "M" }); //Non-Constructor Object Property Initialization
    PersonList.Add(new Person() { Age = 24, Name = "Jack", Gender = "M" });
    PersonList.Add(new Person() { Age = 29, Name = "Billy", Gender = "M" });

    PersonList.Add(new Person() { Age = 33, Name = "Bob", Gender = "M" });
    PersonList.Add(new Person() { Age = 45, Name = "Frank", Gender = "M" });

    PersonList.Add(new Person() { Age = 24, Name = "Anna", Gender = "F" });
    PersonList.Add(new Person() { Age = 29, Name = "Sue", Gender = "F" });
    PersonList.Add(new Person() { Age = 35, Name = "Sally", Gender = "F" });
    PersonList.Add(new Person() { Age = 36, Name = "Jane", Gender = "F" });
    PersonList.Add(new Person() { Age = 42, Name = "Jill", Gender = "F" });

    //Logic: Show me all males that are less than 30 years old.

    Console.WriteLine("");
    //Iterative Method
    Console.WriteLine("List Filter Normal Way:");
    foreach (var p in PersonList)
        if (p.Gender == "M" && p.Age < 30)
            Console.WriteLine(p.Name + " is " + p.Age);

    Console.WriteLine("");
    //Lambda Filter Method
    Console.WriteLine("List Filter Lambda Way");
    foreach (var p in PersonList.Where(p => (p.Gender == "M" && p.Age < 30))) //.Where is an extension method
        Console.WriteLine(p.Name + " is " + p.Age);

    Console.WriteLine("");
    //LINQ Query Method
    Console.WriteLine("List Filter LINQ Way:");
    foreach (var v in from p in PersonList
                      where p.Gender == "M" && p.Age < 30
                      select new { p.Name, p.Age })
        Console.WriteLine(v.Name + " is " + v.Age);
}

private class Person
{
    public Person() { }
    public int Age { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
}

#endregion

14

List<T>एक FindAllविधि है जो आपके लिए फ़िल्टरिंग करेगी और सूची का सबसेट वापस करेगी।

MSDN का यहाँ एक बेहतरीन कोड उदाहरण है: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

संपादित करें: इससे पहले कि मैं LINQ और Where()विधि की अच्छी समझ रखता था, मैंने इसे लिखा था । अगर मैं आज यह लिखता तो शायद मैं ऊपर जोर्ज उल्लेख का उपयोग करता। FindAllपद्धति अभी भी काम करता है अगर आप एक .NET 2.0 वातावरण हालांकि में अटक कर रहे हैं।


4
Linq ठीक है, लेकिन कम से कम एक परिमाण धीमा है, इसलिए FindAll और फ़िल्टरिंग एक्सटेंशन विधियों (सरणी में उदाहरण के लिए उनमें से एक गुच्छा है) जो IEnumerable पर भरोसा नहीं करते हैं, उन परिदृश्यों के लिए अभी भी समझ में आता है जहां प्रदर्शन मायने रखता है। (एफडब्ल्यूआईडब्लू, मुझे
लिनक

वहाँ एक कारण यह स्वीकार किए जाते हैं जवाब नहीं है? यह तेज प्रतीत होता है और सिंटैक्स अंत में स्पष्ट (कोई भी सूची नहीं है) (कॉल) है।
रैन लोटेम

6

आप अस्थायी सूची की आवश्यकता को समाप्त करने के लिए IEnumerable का उपयोग कर सकते हैं।

public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection)
{
    foreach (T item in collection)
    if (Matches<T>(item))
    {
        yield return item;
    }
}

जहाँ मिलान आपके फ़िल्टर विधि का नाम है। और आप इस तरह का उपयोग कर सकते हैं:

IEnumerable<MyType> filteredItems = GetFilteredItems(myList);
foreach (MyType item in filteredItems)
{
    // do sth with your filtered items
}

यह जरूरत पड़ने पर GetFilteredItems फ़ंक्शन को कॉल करेगा और कुछ मामलों में जो आप फ़िल्टर्ड संग्रह में सभी वस्तुओं का उपयोग नहीं करते हैं, यह कुछ अच्छा प्रदर्शन लाभ प्रदान कर सकता है।


4

जगह में ऐसा करने के लिए, आप "सूची <>" वर्ग के RemoveAll पद्धति का उपयोग कर सकते हैं साथ ही एक कस्टम "प्रेडिकेट" वर्ग के साथ ... लेकिन यह सब कोड को साफ करता है ... हुड के तहत यह वही कर रहा है बात आप कर रहे हैं ... लेकिन हाँ, यह जगह में है, तो आप एक ही अस्थायी सूची है।


4

आप सूची के FindAll पद्धति का उपयोग कर सकते हैं, फ़िल्टर करने के लिए एक प्रतिनिधि प्रदान करते हैं। हालाँकि, मैं @ IainMH से सहमत हूँ कि जब तक यह एक बहुत बड़ी सूची नहीं है, तब तक अपने आप को बहुत ज्यादा चिंता करने लायक नहीं है।


3

यदि आप C # 3.0 का उपयोग कर रहे हैं, तो आप linq का उपयोग कर सकते हैं

या, यदि आप चाहें, तो C # 3 संकलक द्वारा प्रदान किए गए विशेष क्वेरी सिंटैक्स का उपयोग करें:

var filteredList = from x in myList
                   where x > 7
                   select x;

3

LINQ का उपयोग सूचियों की FindAllविधि में दिए गए एक विधेय का उपयोग करने की तुलना में अपेक्षाकृत धीमा है । LINQ के साथ सावधान रहें क्योंकि listजब तक आप परिणाम तक नहीं पहुंचते तब तक की गणना वास्तव में निष्पादित नहीं होती है। इसका मतलब यह हो सकता है कि, जब आपको लगता है कि आपने एक फ़िल्टर की गई सूची बनाई है, तो सामग्री भिन्न हो सकती है जो आपने अपेक्षा की थी जब आप वास्तव में इसे पढ़ते हैं।


1

यदि आपकी सूची बहुत बड़ी है और आप बार-बार फ़िल्टर कर रहे हैं - तो आप फ़िल्टर विशेषता पर मूल सूची को सॉर्ट कर सकते हैं, प्रारंभ और समाप्ति बिंदुओं को खोजने के लिए द्विआधारी खोज।

प्रारंभिक समय ओ (एन * लॉग (एन)) फिर ओ (लॉग (एन))।

मानक फ़िल्टरिंग में हर बार O (n) लगेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.