2011-06-09 8 views
14

मुझे आश्चर्य है कि क्या मैं इस बात पर सर्वसम्मति प्राप्त कर सकता हूं कि तत्वों का एक अलग सेट बनाने के लिए कौन सी विधि बेहतर तरीका है: C# HashSet या IEnumerable's .Distinct() का उपयोग करके, जो एक लिंक फ़ंक्शन है?विशिष्ट डेटा संरचनाओं के निर्माण के लिए बेहतर क्या है: हैशसेट या लिंक की विशिष्ट()?

मान लीजिए कि मैं DataReader साथ डीबी से क्वेरी परिणामों के माध्यम से पाशन कर रहा हूँ, और मेरे विकल्प वस्तुओं मैं एक List<SomeObject> करने के लिए या एक HashSet<SomeObject>List विकल्प के साथ करने के लिए निर्माण को जोड़ने के लिए कर रहे हैं, मैं हवा की तरह कुछ करने के लिए हो रही हैं :

myList = myList.Distinct().ToList<SomeObject>();

HashSet साथ

, मेरी समझ है कि यह करने के लिए तत्वों को जोड़ने से ही गैर दोहराव का ख्याल रखता है, यह मानते हुए आप SomeObject में GetHashCode() और Equals() तरीकों overrided किया है। मैं मुख्य रूप से विकल्पों के जोखिम और प्रदर्शन पहलुओं से चिंतित हूं।

धन्यवाद।

उत्तर

2

"बेहतर" उपयोग करने के लिए एक मुश्किल शब्द है - इसका मतलब विभिन्न लोगों के लिए कई अलग-अलग चीजें हो सकता है।

पठनीयता के लिए, मैं Distinct() के लिए जाऊंगा क्योंकि मुझे व्यक्तिगत रूप से यह अधिक समझदार लगता है।

प्रदर्शन के लिए, मुझे संदेह है कि हाथ से तैयार किए गए हैशसेट कार्यान्वयन हल्के ढंग से तेज हो सकता है - लेकिन मुझे संदेह है कि यह Distinct के आंतरिक कार्यान्वयन के रूप में बहुत अलग होगा, इसमें कोई संदेह नहीं है कि वह स्वयं के कुछ प्रकार का हैशिंग का उपयोग करता है।

जो मैं "सर्वश्रेष्ठ" कार्यान्वयन के रूप में सोचता हूं उसके लिए ... मुझे लगता है कि आपको Distinct का उपयोग करना चाहिए, लेकिन किसी भी तरह से इसे डेटाबेस परत पर धक्का देना चाहिए - यानी डेटारेडर को भरने से पहले अंतर्निहित डेटाबेस चयन बदलें।

1

बड़े संग्रह के लिए हैशसेट तेजी से होने की संभावना है। यह ऑब्जेक्ट्स के हैशकोड पर निर्भर करता है कि यह निर्धारित करने के लिए कि सेट में कोई तत्व पहले से मौजूद है या नहीं।

प्रैक्टिस में, यह (सबसे अधिक संभावना) कोई फर्क नहीं पड़ता (लेकिन अगर आपको परवाह है तो आपको मापना चाहिए)।

मैंने सहजता से पहले अनुमान लगाया कि HashSet तेज़ हैश की जांच करने के कारण तेज़ी से होगा। हालांकि, मैंने संदर्भ स्रोतों में विशिष्ट के वर्तमान (4.0) कार्यान्वयन को देखा, और यह कवर के तहत समान Set वर्ग (जो हैशिंग पर भी निर्भर करता है) का उपयोग करता है। निष्कर्ष; कोई व्यावहारिक प्रदर्शन अंतर नहीं है।

आपके मामले के लिए, मैं .Distinct के साथ पठनीयता के लिए जाऊंगा - यह स्पष्ट रूप से कोड के इरादे को व्यक्त करता है। हालांकि, मैं अन्य उत्तरों में से एक के साथ सहमत हूं, यदि संभव हो तो आपको शायद डीबी में इस ऑपरेशन को निष्पादित करना चाहिए।

0

डिस्टिंट का कार्यान्वयन हैशसेट का उपयोग कर सकता है। Jon Skeet's Edulinq implementation पर एक नज़र डालें।

8

क्या बेहतर है आपके इरादे का वर्णन करने का सबसे अधिक अभिव्यक्तिपूर्ण है। आंतरिक कार्यान्वयन विवरण समान या कम होने वाला है, अंतर यह है कि "कोड कौन लिख रहा है?"अपने इरादा एक स्रोत है कि नहीं है कहा मदों की एक संग्रह से जमीन से मदों की एक अलग संग्रह बनाने के लिए है

हैं, मैं HashSet<T> के लिए तर्क है। आप आइटम बनाने के लिए है, आप संग्रह का निर्माण करने के लिए है, तुम भी शुरू से ही एक अन्यथा निर्माण हो सकता है।

, अगर आप पहले से ही आइटम का संग्रह है और आप मुझे Distinct() लागू के लिए तर्क है डुप्लिकेट को निकाल करना चाहते हैं,। आप पहले से ही एक संग्रह है, आप बस अलग आइटम प्राप्त करने के लिए एक अभिव्यक्तिपूर्ण तरीका चाहते हैं।

+0

+1 केवल उचित उत्तर के लिए! – nawfal

1

यदि कोई डैशरडर के परिणामों के माध्यम से आपके लूट को जोड़ना एक हैशसेट में जोड़ना, तो उसे सूची में जोड़ने और उस पर एक अंतर करने से बेहतर होगा। आप एक पुनरावृत्ति को बचाएंगे। (अलग आंतरिक रूप से हैशसेट का उपयोग करता है)

11

एंथनी पेगम ने इसे सर्वश्रेष्ठ कहा है। इस काम के लिए सही उपकरण का उपयोग करें। मैं ऐसा इसलिए कहता हूं क्योंकि प्रदर्शन के समय Distinct या HashSet इतना बड़ा नहीं है। संग्रह को HashSet का उपयोग करें जब संग्रह हमेशा अलग-अलग सामानों को रखना चाहिए। यह प्रोग्रामर को यह भी बताता है कि आप इसमें डुप्लिकेट जोड़ नहीं सकते हैं। एक सामान्य List<T> और .Distinct() का उपयोग करें जब आपको डुप्लीकेट जोड़ना होगा और बाद में डुप्लीकेट हटा देना होगा। इरादा मायने रखता है।

सामान्य तौर पर,

एक) एक HashSet अगर आप डाटाबेस से नई वस्तुओं जोड़ रहे हैं और आप अपने स्वयं की एक कस्टम Equals निर्दिष्ट नहीं किया है किसी भी अच्छे कार्य न करें। डीबी से प्रत्येक ऑब्जेक्ट आपके हैशसेट के लिए एक नया उदाहरण हो सकता है (यदि आप केवल नए हैं) और इससे संग्रह में डुप्लीकेट हो जाएंगे। उस मामले में सामान्य List<T> का उपयोग करें।

बी) यदि आपके पास हैशसेट के लिए परिभाषित समानता तुलनाकर्ता है, और आपके संग्रह को हमेशा केवल विशिष्ट वस्तुओं को रखना चाहिए, हैशसेट का उपयोग करना चाहिए।

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

डी) सबसे अच्छी बात यह है कि आपको डेटाबेस में डुप्लीकेट हटाने का कार्य देना है, सही उपकरण और यह पहली कक्षा है!

प्रदर्शन के अंतर के रूप में, मेरे परीक्षण में मुझे हमेशा हैशसेट तेजी से पाया जाता है, लेकिन फिर यह केवल मामूली है। यह स्पष्ट रूप से सूची दृष्टिकोण के साथ विचार कर रहा है जिसे आपको पहले जोड़ना है और फिर उस पर एक विशिष्ट कार्य करना है।

टेस्ट विधि: दो सामान्य कार्यों के साथ शुरू,

public static void Benchmark(Action method, int iterations = 10000) 
{ 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
    for (int i = 0; i < iterations; i++) 
     method(); 

    sw.Stop(); 
    MsgBox.ShowDialog(sw.Elapsed.TotalMilliseconds.ToString()); 
} 

public static List<T> Repeat<T>(this ICollection<T> lst, int count) 
{ 
    if (count < 0) 
     throw new ArgumentOutOfRangeException("count"); 

    var ret = Enumerable.Empty<T>(); 

    for (var i = 0; i < count; i++) 
     ret = ret.Concat(lst); 

    return ret.ToList(); 
} 

कार्यान्वयन:

var d = Enumerable.Range(1, 100).ToList().Repeat(100); 
HashSet<int> hash = new HashSet<int>(); 

Benchmark(() => 
{ 
    hash.Clear(); 
    foreach (var item in d) 
    { 
     hash.Add(item); 
    } 
}); 

~ 3300 एमएस

var d = Enumerable.Range(1, 100).ToList().Repeat(100); 
List<int> list = new List<int>(); 

Benchmark(() => 
{ 
    list.Clear(); 
    foreach (var item in d) 
    { 
     list.Add(item); 
    } 

    list = list.Distinct().ToList(); 
}); 

~ 5800 एमएस

2,5 सेकंड के एक अंतर 10000 वस्तुओं की एक सूची के लिए बुरा नहीं है जब एक और 10000 बार दोहराया। सामान्य मामलों के लिए अंतर शायद ही ध्यान देने योग्य होगा।

सबसे अच्छा अपने वर्तमान डिजाइन के साथ आप के लिए संभवतः दृष्टिकोण:

var d = Enumerable.Range(1, 100).ToList().Repeat(100); 
HashSet<int> hash = new HashSet<int>(); 
List<int> list = new List<int>(); 

Benchmark(() => 
{ 
    hash.Clear(); 
    foreach (var item in d) 
    { 
     hash.Add(item); 
    } 

    list = hash.ToList(); 
}); 

~ 3300 एमएस

कोई महत्वपूर्ण अंतर नहीं है, देखते हैं ..


आंशिक असंबंधित - इस उत्तर को पोस्ट करने के बाद, मुझे यह जानकर उत्सुकता थी कि इसमें सबसे अच्छा तरीका क्या है एक सामान्य सूची से डुप्लिकेट को हटा रहा है।

var d = Enumerable.Range(1, 100).ToList().Repeat(100); 
HashSet<int> hash = new HashSet<int>(); 
List<int> list = new List<int>(); 

Benchmark(() => 
{ 
    hash = new HashSet<int>(d); 
}); 

~ 3900 एमएस

var d = Enumerable.Range(1, 100).ToList().Repeat(100); 
List<int> list = new List<int>(); 

Benchmark(() => 
{ 
    list = d.Distinct().ToList(); 
}); 

~ 3200 एमएस

यहाँ सही उपकरण Distinct hackish HashSet की तुलना में तेजी है! शायद यह हैश सेट बनाने का ओवरहेड है।


मैंने संदर्भ सूची जैसे विभिन्न अन्य संयोजनों के साथ परीक्षण किया है, मूल सूची में डुप्लीकेट के बिना आदि परिणाम लगातार हैं।

संबंधित मुद्दे