LINQ। किसी भी व्यक्ति .Exists - क्या अंतर है?


413

संग्रह पर LINQ का उपयोग करना, कोड की निम्नलिखित लाइनों के बीच क्या अंतर है?

if(!coll.Any(i => i.Value))

तथा

if(!coll.Exists(i => i.Value))

अपडेट १

जब मैं जुदा .Existsहोता हूं तो ऐसा लगता है कि कोई कोड नहीं है।

अपडेट २

किसी को भी पता है कि इस एक के लिए कोई कोड क्यों नहीं है?


9
आपके द्वारा संकलित कोड कैसा दिखता है? आप कैसे जुदा हो गए? ILDASM? आप क्या खोजने की उम्मीद करते थे लेकिन नहीं किया?
14

जवाबों:


423

प्रलेखन देखें

List.Exists (ऑब्जेक्ट विधि - MSDN)

निर्धारित करता है कि सूची (टी) में ऐसे तत्व हैं जो निर्दिष्ट विधेय द्वारा परिभाषित शर्तों से मेल खाते हैं।

यह .NET 2.0 के बाद से मौजूद है, इसलिए LINQ से पहले। प्रेडिकेटेट प्रतिनिधि के साथ प्रयोग किया जा सकता है , लेकिन लैम्ब्डा अभिव्यक्ति पिछड़े संगत हैं। इसके अलावा, बस सूची में यह (यहां तक ​​कि IList भी नहीं है)

IEnumerable.Any (विस्तार विधि - MSDN)

निर्धारित करता है कि किसी अनुक्रम का कोई तत्व किसी स्थिति को संतुष्ट करता है या नहीं।

यह .NET 3.5 में नया है और फंक (TSource, bool) को तर्क के रूप में उपयोग करता है, इसलिए इसका उद्देश्य लंबोदर भाव और LINQ के साथ उपयोग किया जाना था।

व्यवहार में, ये समान हैं।


4
मैंने बाद में एक और थ्रेड में एक पोस्ट किया, जहां मैंने .NET 2 List<>उदाहरण विधियों के सभी लिनक "समकक्ष" सूचीबद्ध किए।
जेपी स्टिग नीलसन

201

अंतर यह है कि कोई भी IEnumerable<T>System.Linq.Enumerable पर परिभाषित किसी भी के लिए एक विस्तार विधि है । इसका उपयोग किसी भी IEnumerable<T>उदाहरण पर किया जा सकता है ।

अस्तित्व एक विस्तार विधि प्रतीत नहीं होती है। मेरा अनुमान है कि टक प्रकार का है List<T>। यदि हां, तो एक उदाहरण एक विधि है, जो किसी भी के समान कार्य करता है।

संक्षेप में , विधियां अनिवार्य रूप से समान हैं। एक दूसरे की तुलना में अधिक सामान्य है।

  • किसी भी में एक अधिभार होता है जो कोई पैरामीटर नहीं लेता है और बस गणना करने योग्य किसी भी वस्तु की तलाश करता है।
  • अस्तित्व के पास ऐसा कोई अधिभार नहीं है।

13
अच्छी तरह से (+1)। सूची <T> .Exists .Net 2 के बाद से आसपास है लेकिन केवल सामान्य सूचियों के लिए काम करता है। IEnumerable <T>। किसी भी। संग्रह पर काम करता है कि एक विस्तार के रूप में .Net 3 में जोड़ा गया था। सूची <T> जैसे भी ऐसे ही सदस्य हैं। एक संपत्ति और IEnumerable <T> .ाउंट () - एक विधि है।
कीथ

51

TLDR; प्रदर्शन-वार Anyधीमा प्रतीत होता है (यदि मैंने लगभग एक ही समय में दोनों मानों का मूल्यांकन करने के लिए इसे ठीक से स्थापित किया है)

        var list1 = Generate(1000000);
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s +=" Any: " +end1.Subtract(start1);
            }

            if (!s.Contains("sdfsd"))
            {

            }

परीक्षण सूची जनरेटर:

private List<string> Generate(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            list.Add( new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    new RNGCryptoServiceProvider().GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray())); 
        }

        return list;
    }

10M रिकॉर्ड के साथ

"कोई भी: 00: 00: 00.3770377 अस्तित्व: 00: 00: 00.2490249"

5M रिकॉर्ड के साथ

"कोई भी: 00: 00: 00.0940094 अस्तित्व: 00: 00: 00.1420142"

1M रिकॉर्ड के साथ

"कोई भी: 00: 00: 00.0180018 अस्तित्व: 00: 00: 00.0090009"

500k के साथ, (मैं भी उस क्रम के आसपास फ़्लिप हो गया जिसमें वे यह देखने के लिए मूल्यांकन करते हैं कि क्या कोई अतिरिक्त ऑपरेशन नहीं है जो पहले रन से जुड़ा हो।)

"अस्तित्व: 00: 00: 00.0050005 कोई भी: 00: 00: 00.0100010"

100k रिकॉर्ड के साथ

"अस्तित्व: 00: 00: 00.0010001 कोई भी: 00: 00: 00.0020002"

यह Any2 की परिमाण से धीमा प्रतीत होगा ।

संपादित करें: 5 और 10M रिकॉर्ड के लिए, मैंने जिस तरह से यह सूची बनाता है और Existsअचानक धीमी हो गई है, Anyजिसका अर्थ है कि मैं परीक्षण कर रहा हूं जिस तरह से कुछ गलत है।

नया परीक्षण तंत्र:

private static IEnumerable<string> Generate(int count)
    {
        var cripto = new RNGCryptoServiceProvider();
        Func<string> getString = () => new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    cripto.GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray());

        var list = new ConcurrentBag<string>();
        var x = Parallel.For(0, count, o => list.Add(getString()));
        return list;
    }

    private static void Test()
    {
        var list = Generate(10000000);
        var list1 = list.ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {

            }
        }

Edit2: ठीक है इसलिए परीक्षण डेटा उत्पन्न करने से किसी भी प्रभाव को खत्म करने के लिए मैंने इसे फाइल करने के लिए लिखा है और अब इसे वहां से पढ़ें।

 private static void Test()
    {
        var list1 = File.ReadAllLines("test.txt").Take(500000).ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {
            }
        }
    }

10M

"कोई भी: 00: 00: 00.1640164 अस्तित्व: 00: 00: 00.0750075"

5M

"कोई भी: 00: 00: 00.0810081 अस्तित्व: 00: 00: 00.0360036"

1M

"कोई भी: 00: 00: 00.0190019 अस्तित्व: 00: 00: 00.0070007"

500k

"कोई भी: 00: 00: 00.0120012 अस्तित्व: 00: 00: 00.0040004"

यहां छवि विवरण दर्ज करें


3
आपकी कोई बदनामी नहीं, लेकिन मुझे इन बेंचमार्क पर संदेह हो रहा है। संख्या देखें: प्रत्येक परिणाम में एक पुनरावृत्ति हो रही है (3770377: 2490249)। कम से कम मेरे लिए, यह एक निश्चित संकेत है कि कुछ सही नहीं है। मैं यहाँ मैथ्स पर सौ प्रतिशत यकीन नहीं कर रहा हूँ, लेकिन मुझे लगता है कि उस आवर्ती पैटर्न की संभावना 1 से 999 ^ 999 (या 999? हो सकता है?) प्रति मूल्य है। तो लगातार 8 बार ऐसा होने की संभावना असीम है। मुझे लगता है कि यह इसलिए है क्योंकि आप बेंचमार्किंग के लिए डेटटाइम का उपयोग करते हैं ।
जेर्री कंगासनीमे

@JerriKangasniemi अलगाव में एक ही ऑपरेशन को दोहराते हुए हमेशा समान मात्रा में समय लेना चाहिए, वही कई बार दोहराता है। आप क्या कहते हैं कि यह डेटाइम है?
माटस वैतकेविसियस

बिलकुल यह करता है। समस्या अभी भी है कि 500k कॉल के लिए 0120012 सेकंड उदाहरण के लिए इसे लेने की संभावना नहीं है। और अगर यह पूरी तरह से रैखिक होगा, तो इस प्रकार संख्याओं को इतनी अच्छी तरह से समझाते हुए, 1M कॉल में 0240024 सेकंड (दो बार लंबे समय तक) लगेंगे, हालांकि ऐसा नहीं है। 1M कॉल में 58, (3)% 500k से अधिक और 10M में 5M की तुलना में 102,5% अधिक समय लगता है। तो यह एक रेखीय कार्य नहीं है और इस प्रकार सभी पुनरावृत्ति की संख्या के लिए वास्तव में उचित नहीं है। मैंने डेटटाइम का उल्लेख किया है क्योंकि मैंने खुद के साथ अतीत में समस्याओं का अनुभव किया है, क्योंकि डेटटाइम उच्च परिशुद्धता टाइमर का उपयोग नहीं कर रहा है।
जेर्री कंगासनीमे

2
@JerriKangasniemi क्या मैं आपको सुझाव दे सकता हूं कि आप इसे ठीक करें और उत्तर पोस्ट करें
Matas Vaitkevicius

1
अगर मैं आपके परिणामों को सही ढंग से पढ़ रहा हूं, तो आपने किसी भी समय केवल 2 से 3 गुना होने की सूचना दी है। मैं यह नहीं देखता कि कैसे डेटा भी हल्के से आपके दावे का समर्थन करता है कि "यह किसी भी 2 के परिमाण द्वारा धीमा प्रतीत होता है"। यह थोड़ा धीमा है, निश्चित है, परिमाण के आदेश नहीं।
Suncat2000

16

बेंचमार्किंग पर माटस के जवाब पर एक निरंतरता के रूप में ।

TL / DR : अस्तित्व () और कोई भी () समान रूप से तेज़ हैं।

सबसे पहले: स्टॉपवॉच का उपयोग करते हुए बेंचमार्किंग सटीक नहीं है ( एक अलग, लेकिन परिचित, विषय पर सीरीज़ का जवाब देखें ), लेकिन यह डेटाइम की तुलना में कहीं अधिक सटीक है।

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

static void Main(string[] args)
    {
        Console.WriteLine("Generating list...");
        List<string> list = GenerateTestList(1000000);
        var s = string.Empty;

        Stopwatch sw;
        Stopwatch sw2;
        List<long> existsTimes = new List<long>();
        List<long> anyTimes = new List<long>();

        Console.WriteLine("Executing...");
        for (int j = 0; j < 1000; j++)
        {
            sw = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw.Stop();
                existsTimes.Add(sw.ElapsedTicks);
            }
        }

        for (int j = 0; j < 1000; j++)
        {
            sw2 = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw2.Stop();
                anyTimes.Add(sw2.ElapsedTicks);
            }
        }

        long existsFastest = existsTimes.Min();
        long anyFastest = anyTimes.Min();

        Console.WriteLine(string.Format("Fastest Exists() execution: {0} ticks\nFastest Any() execution: {1} ticks", existsFastest.ToString(), anyFastest.ToString()));
        Console.WriteLine("Benchmark finished. Press any key.");
        Console.ReadKey();
    }

    public static List<string> GenerateTestList(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            Random r = new Random();
            int it = r.Next(0, 100);
            list.Add(new string('s', it));
        }
        return list;
    }

उपरोक्त कोड को निष्पादित करने के बाद 4 बार (जो बदले में 1 000 करते हैं Exists() और Any()1 000 000 तत्वों के साथ एक सूची पर), यह देखना मुश्किल नहीं है कि तरीके बहुत अधिक समान रूप से तेज़ हैं।

Fastest Exists() execution: 57881 ticks
Fastest Any() execution: 58272 ticks

Fastest Exists() execution: 58133 ticks
Fastest Any() execution: 58063 ticks

Fastest Exists() execution: 58482 ticks
Fastest Any() execution: 58982 ticks

Fastest Exists() execution: 57121 ticks
Fastest Any() execution: 57317 ticks

वहाँ है कुछ अंतर है, लेकिन यह बहुत छोटा एक फर्क करने के लिए पृष्ठभूमि शोर से नहीं समझाया जा रहा है। मेरा अनुमान है कि यदि कोई १० ००० या १००००० करेगा Exists()और Any()इसके बजाय, वह मामूली अंतर कम या ज्यादा गायब हो जाएगा।


क्या मैं आपको सुझाव दे सकता हूं कि आप 10 000 और 100 000 और 1000000 करें, बस इस बारे में व्यवस्थित होना चाहिए, यह भी कि न्यूनतम और औसत मूल्य क्यों नहीं?
माटस वैटकेविसियस

2
न्यूनतम मूल्य है क्योंकि मैं प्रत्येक विधि के सबसे तेज़ निष्पादन (= संभवतः कम से कम पृष्ठभूमि शोर) की तुलना करना चाहता हूं। मैं इसे अधिक पुनरावृत्तियों के साथ कर सकता हूं, हालांकि यह बाद में होगा (मुझे संदेह है कि मेरे बॉस हमारे बैकलॉग के माध्यम से काम करने के बजाय मुझे ऐसा करने के लिए भुगतान करना चाहते हैं)
जेर्री कंगासनीमी

कम से कम करने के संबंध में है औसत उपयोग करने के लिए) मैं अपने तर्क हालांकि अधिक रूढ़िवादी दृष्टिकोण देख सकते हैं, मैं पॉल लिंडबर्ग कहा है और वह कहते हैं कि यह ठीक है है en.wikipedia.org/wiki/Algorithmic_efficiency#Practice
Matas Vaitkevicius

9
यदि आपके द्वारा पोस्ट किया गया कोड वह है जिसे आपने वास्तव में निष्पादित किया है तो आश्चर्य की बात नहीं है कि आपको समान परिणाम मिलते हैं, जैसा कि आप दोनों मापों में एक्ज़िस्ट कहते हैं। ;)
साइमन टचटेक

हे, हाँ, मैंने देखा कि अब आप भी इसे कहते हैं। हालांकि मेरे निष्पादन में नहीं। इसका मतलब यह था कि मैं जो तुलना कर रहा था उसकी एक छीन ली गई अवधारणा के रूप में। : पी
जेरि कंगासनेमी

4

इसके अतिरिक्त, यह तभी काम करेगा जब मान टाइप बूल का हो। आम तौर पर यह विधेय के साथ प्रयोग किया जाता है। किसी भी विधेय का आमतौर पर उपयोग किया जाएगा कि क्या कोई तत्व किसी दिए गए शर्त को पूरा करता है। यहां आप बस अपने तत्व i से बूल प्रॉपर्टी का मैप बना रहे हैं। यह एक "i" की खोज करेगा जिसकी मूल्य संपत्ति सत्य है। एक बार करने के बाद, विधि सच हो जाएगी।


3

जब आप माप सही करते हैं - जैसा कि ऊपर बताया गया है: कोई भी और मौजूद है, और औसत जोड़कर - हम निम्न आउटपुट प्राप्त करेंगे:

Executing search Exists() 1000 times ... 
Average Exists(): 35566,023
Fastest Exists() execution: 32226 

Executing search Any() 1000 times ... 
Average Any(): 58852,435
Fastest Any() execution: 52269 ticks

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