2010-03-09 33 views
8

मैंने पहले कई लैम्ब्डा अभिव्यक्तियों का उपयोग नहीं किया है और मैं ऐसे मामले में भाग गया जहां मैंने सोचा कि मैं एक का उपयोग कर सकता हूं। मेरे पास ~ 1 9, 000 रिकॉर्ड की एक कस्टम सूची है और मुझे यह पता लगाने की ज़रूरत है कि सूची में कोई रिकॉर्ड मौजूद है या नहीं, इसलिए सूची में जाने के लिए लूप का एक समूह लिखने या लिनक का उपयोग करने के बजाय मैंने इसे आजमाने का फैसला किया:सी # लैम्ब्डा अभिव्यक्ति स्पीड

for (int i = MinX; i <= MaxX; ++i) 
{ 
    tempY = MinY; 

    while (tempY <= MaxY) 
    { 
     bool exists = myList.Exists(item => item.XCoord == i && item.YCoord == tempY); 

     ++tempY; 
    } 
} 

निष्पादित करने में केवल 9 -11 सेकेंड लगते हैं। क्या मैं कुछ गलत कर रहा हूं क्या यह सिर्फ एक मामला है जहां मुझे इस तरह की अभिव्यक्ति का उपयोग नहीं करना चाहिए?

धन्यवाद।

संपादित करें: क्षमा करें। मुझे विस्तार करना चाहिए। मैं लूप के लिए रिकॉर्ड के साथ एक सूची बना रहा हूं और जांच कर रहा हूं कि यह रिकॉर्ड मेरी सूची में मौजूद है या नहीं। यही एकमात्र तरीका है जिसके बारे में मैं सोचने के बारे में सोच सकता हूं। मैं इसका पुनर्मूल्यांकन करूंगा और देख सकता हूं कि मैं क्या कर रहा हूं।

+0

आप इसे तेजी से क्यों उम्मीद करेंगे? यह किसी भी प्रकार की इंडेक्सिंग या सॉर्टिंग के बिना घोंसला वाली खोज है। –

+0

मुझे नहीं लगता कि नीचे वोट आवश्यक है। यह एक दिलचस्प समस्या है, हालांकि खराब शब्द। – kervin

+0

बाहरी लूप लूप के लिए क्यों है, लेकिन अंदरूनी एक लूप? – Ponkadoodle

उत्तर

6

आपका एल्गोरिदम अक्षम है। यदि आप एक ही सूची में कई खोज कर रहे हैं तो आपको:

  1. Sort सूची उचित रूप से (आपकी लुकअप कुंजी द्वारा) की आवश्यकता है।
  2. सही रिकॉर्ड खोजने के लिए binary search का उपयोग करें।

आपका दूसरा विकल्प यह है कि अगर स्मृति कोई मुद्दा नहीं है और आप वास्तव में तेज़ी से होना चाहते हैं तो रिकॉर्ड को Dictionary<Your_Key,Record> में रखना है। यह आपके सेटअप के बाद आपको सबसे तेज पहुंच देगा।

+0

यह वास्तव में अच्छी तरह से काम किया। जो कुछ मैं चाहता था उसे करने के लिए केवल 1 सेकंड लिया। – Nathan

7

यह लैम्ब्डा के साथ कोई समस्या नहीं है, यह आपके एल्गोरिदम के साथ एक समस्या है। आप मिनएक्स से मैक्सएक्स तक लूप कर रहे हैं जो कितने हैं? तो आप मिनीवाई से अधिकतम तक लूपिंग कर रहे हैं, तो आप ~ 1 9, 000 रिकॉर्ड के माध्यम से लूप कर रहे हैं। इसलिए यदि एक्स लूप 10 है और वाई लूप 10 है, तो आप 1 9, 000 * 10 * 10 कॉल कर रहे हैं। इससे भी बहुत बुरा हो सकता था।

2

क्या आप यह नहीं चाहते हैं?

myList.Where(
    item=>item.XCoord>=MinX 
     &&item.XCoord<=MaxX 
     &&item.YCoord>=MinY 
     &&item.YCoord<=MaxY 
) 

सभी जिसके परिणामस्वरूप आइटम exists कसौटी को संतुष्ट करेगा।

... या मैंने गलत समझा?

12

यह कोड मुझे कोई समझ नहीं आता है, इसलिए यह कहना मुश्किल है कि आप इसे गलत कर रहे हैं या नहीं। बाधाएं अच्छी हैं कि हाँ, आप इसे गलत कर रहे हैं।

कोड दिखाने के बजाय, इसे आज़माएं। मान लें कि आपके पास एक विधि थी जिसने बिल्कुल जो आप चाहते थे। उस विधि के हस्ताक्षर क्या होगा? शरीर नहीं, सिर्फ हस्ताक्षर।

मान लीजिए उदाहरण के लिए आप सवाल पूछना चाहते हैं "क्या इस बिंदु की सूची में एक विशेष बिंदु है?" तब हस्ताक्षर होगा

bool Contains(List<Point> list, Point p) 

मान लीजिए आप सवाल पूछना चाहता हूँ "अंक की इस सूची में इस आयत के अंदर किसी भी बिंदु को शामिल करता है?" फिर हस्ताक्षर

bool ContainsAny(List<Point> list, Rectangle r) 

मान लीजिए कि आप सवाल पूछना चाहते हैं "इन दोनों सूचियों में क्या मुद्दे हैं?"तो हस्ताक्षर

List<Point> Intersection(List<Point> l1, List<Point> l2) 

और इतने पर किया जाएगा। राज्य आप अधिक स्पष्ट रूप से करने के लिए कोशिश कर रहे हैं और हम मदद कर सकते हैं कि आपरेशन का अनुकूलन। हस्ताक्षर के साथ शुरू करो।

+0

क्या ऊपर मेरा संपादन मदद करता है? गलतफहमी के लिए खेद है। – Nathan

+0

+1 क्योंकि यह वास्तव में नाथन की तरह दिखता है मैन्युअल रूप से 'प्वाइंट' बना रहा है, जब वह वास्तव में केवल अंक की सामान्य सूची संग्रहीत कर सकता है और 'ContainsAny' का उपयोग कर सकता है। –

1

मैं विस्तार करने के लिए जा रहा हूँ

एक अच्छा LINQ आधारित समाधान के साथ केविन के जवाब पर। मूल कोड प्रभावी रूप से एक दो आयामी बूलियन सरणी अगर एक x & y पर myList में ही अस्तित्व में निर्देशांक प्रत्येक सरणी तत्व के लिए निर्देशांक का संकेत गणना की।

,

Func<int, int, bool> original = 
    (x, y) => 
     myList.Exists(item => item.XCoord == x && item.YCoord == y); 

इस रूप में Exists विधि कहा जाता है अक्षम है, और इसलिए सूची दोहराया है प्रत्येक x & y के लिए:

प्रत्येक x & y के लिए इस्तेमाल किया परीक्षण के रूप में एक लैम्ब्डा समारोह के रूप में व्यक्त किया जा सकता समन्वय परीक्षण किया। पूरी सूची को फिर से चालू किया गया है या नहीं, यह निर्भर करता है कि कोई मिलान मिलता है या नहीं। कई मामलों में एक मैच नहीं होगा इसलिए पूरी सूची कई बार देखी जाती है।

इसलिए यह शब्दकोशों का एक शब्दकोश पूर्व गणना करने के लिए निर्धारित करने के लिए एक समन्वय किसी भी x & y समन्वय के लिए myList में मौजूद रहने पर सबसे अच्छा है।

var xyLookup = 
    (from item in myList 
    group item by item.XCoord into XCoords 
    select new 
    { 
     X = XCoords.Key, 
     YLookup = (from x in XCoords 
        group x by x.YCoord into YCoords 
        select new 
        { 
         Y = YCoords.Key, 
         Coords = YCoords 
        }).ToDictionary(a => a.Y, a => a.Coords) 
    }).ToDictionary(b => b.X, b => b.YLookup); 

xyLookup अब मूल संस्करण को बदलने के लिए निम्नलिखित लैम्ब्डा समारोह की अनुमति देता है।

Func<int, int, bool> refactored = 
    (x, y) => 
     xyLookup.ContainsKey(x) && xyLookup[x].ContainsKey(y); 

पूर्व कंप्यूटिंग xyLookup मेरी परीक्षण के अनुसार, कुछ समय तो लगता है, अगर मैं एक 3x3 सरणी है और myList शामिल 3 निर्देशांक तो दोनों तरीकों लगभग एक ही गति कर रहे हैं। हालांकि, मैं उम्मीद करता हूं कि वास्तविक सरणी आकार और myList में तत्वों की संख्या अभ्यास में बहुत बड़ी होगी।

यदि मेरे पास myList में 10,000 निर्देशांक के साथ 100x100 सरणी है तो xyLookup मूल विधि से लगभग 9 गुना तेज है।

मुझे linq पसंद है ... :-)

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