2008-08-25 8 views
92

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

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

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

+0

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

उत्तर

151

आप सी # 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(); 
+16

जहां एक्सटेंशन विधि IENumerable लौटाती है, सूची नहीं। यह होना चाहिए: myList.Where (x => x> 7) .सूची() –

+0

आपकी टिप्पणी के लिए धन्यवाद राफा। – David

+1

तारों द्वारा फ़िल्टर करने के लिए यह कैसे काम करता है। "Ch" – joncodo

9

सूची FindAll विधि है कि आप के लिए छानने करते हैं और सूची का एक सबसेट वापस आ जाएगी है।

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

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

+1

लिंक ठीक है, लेकिन कम से कम एक परिमाण धीमा है, इसलिए FindAll और एक्सटेंशन विधियों को फ़िल्टर करना (सरणी में उदाहरण के लिए उनमें से एक समूह है) जो IENumerable पर निर्भर नहीं है, परिदृश्यों के लिए अभी भी समझ में आता है जहां प्रदर्शन महत्वपूर्ण है। (एफडब्ल्यूआईडब्ल्यू, मुझे लिंक और/या आईनेमेरेबल द्वारा सामान्य रूप से आवश्यक कारक 7 से 50 और समय के परिणाम मिलते हैं) – Philm

3

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

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 समारोह कॉल करेंगे और कुछ मामलों है कि आप संग्रह फ़िल्टर्ड में सभी आइटम का उपयोग नहीं करते में, यह कुछ अच्छे प्रदर्शन के लाभ प्रदान कर सकता है।

2

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

1

क्या आप LINQ

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

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

लैम्बडास और 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 
2

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

0

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

आरंभिक समय ओ (एन * लॉग (एन)) तो ओ (लॉग (एन))।

मानक फ़िल्टरिंग प्रत्येक बार ओ (एन) ले जाएगा।