2012-05-14 15 views
11

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

diagram of code purpose

उदाहरण के लिए, पहले खंडों ए-बी, ए सी, ए-डी मिलता है, फिर बी-सी, बी-डी; और अंत में, सी-डी। दूसरे शब्दों में, हम अपने नए सरणी में ए-बी चाहते हैं, लेकिन बी-ए नहीं, क्योंकि यह एक डुप्लिकेशंस होगा।

var pointsArray = new Point[4]; 

pointsArray[0] = new Point(0, 0); 
pointsArray[1] = new Point(10, 0); 
pointsArray[2] = new Point(10, 10); 
pointsArray[3] = new Point(0, 10); 

// using (n * (n-1))/2 to determine array size 
int distArraySize = (pointsArray.Length*(pointsArray.Length - 1))/2; 

var distanceArray = new double[distArraySize]; 

int distanceArrayIndex = 0; 

// Loop through points and get distances, never using same point pair twice 
for (int currentPointIndex = 0; currentPointIndex < pointsArray.Length - 1; currentPointIndex++) 
{ 
    for (int otherPointIndex = currentPointIndex + 1; 
      otherPointIndex < pointsArray.Length; 
      otherPointIndex++) 
    { 
     double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X; 
     double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y; 

     double distance = Math.Sqrt(Math.Pow(xDistance, 2) + Math.Pow(yDistance, 2)); 

     // Add distance to distanceArray 
     distanceArray[distanceArrayIndex] = distance; 

     distanceArrayIndex++; 
    } 
} 

इस के बाद से अंक के कई हजारों के साथ इस्तेमाल किया जाएगा, मैं सोच रहा हूँ एक ठीक dimensioned सरणी IEnumerable किसी भी प्रकार का उपयोग करने की तुलना में अधिक कुशल हो जाएगा।

+4

यह अच्छा लगता है। यह दोनों कुशल और काम करेगा। क्या आप इसे कोड समीक्षा में पोस्ट करना चाहते थे? http://codereview.stackexchange.com/ – yamen

+0

@Yamen मुझे उस विकल्प से अवगत नहीं था। क्या कोई तरीका है कि मैं इस सवाल को वहां पर ले जा सकता हूं? धन्यवाद! – Stonetip

+0

मेरी भावना यह है कि यह सबसे अच्छा तरीका है; मानते हैं कि सभी बिंदु अद्वितीय हैं, फिर तार्किक रूप से बिंदुओं के सेट से सभी संयोजन उत्पन्न करने का सबसे अच्छा तरीका पूरे सेट पर एक बार फिर से शुरू करना है, और उसके बाद प्रत्येक पुनरावृत्ति के भीतर उस बिंदु से बाकी हिस्सों में पुनरावृत्ति होती है। एर्गो आप संयोजन 'ए, बी' और 'बी, ए' कभी नहीं उत्पन्न करेंगे।उस ने कहा, यह मानता है कि आपको बिल्कुल * दूरी को स्टोर करने की आवश्यकता है और वास्तव में उन्हें विज्ञापन की गणना करने पर भरोसा नहीं कर सकता है। लेकिन फिर यह आपके प्रश्न के दायरे से बाहर है –

उत्तर

3

यदि आपके पास एन अंक हैं, तो अंकों के सभी जोड़े के सेट में n * (n-1)/2 तत्व होते हैं। यही वह ऑपरेशन है जो आप कर रहे हैं। एकमात्र परिवर्तन मैं समानांतर में संचालन करने के लिए समानांतर। फॉरएच() का उपयोग कर रहा हूं।

कुछ इस तरह (जरूरत डिबगिंग)

 int distArraySize = (pointsArray.Length * (pointsArray.Length - 1))/2; 

     var distanceArray = new double[distArraySize]; 

     int numPoints = pointsArray.Length; 

     Parallel.ForEach<int>(Enumerable.Range(0, numPoints - 2), 
      currentPointIndex => 
      { 
       Parallel.ForEach<int>(Enumerable.Range(currentPointIndex + 1, numPoints - 2), 
        otherPointIndex => 
        { 
         double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X; 
         double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y; 
         double distance = Math.Sqrt(xDistance * xDistance + yDistance * yDistance); 
         int distanceArrayIndex = currentPointIndex * numPoints - (currentPointIndex * (currentPointIndex + 1)/2) + otherPointIndex - 1; 
         distanceArray[distanceArrayIndex] = distance; 
        }); 
      }); 
+0

सुझाव के लिए धन्यवाद। मैं इसे अपने आप लागू करने की कोशिश करूंगा, लेकिन मेरे उदाहरण से संबंधित कोई भी उदाहरण निश्चित रूप से सराहना की जाएगी। – Stonetip

+0

नोट: इस कोड को लूप के लिए समानांतर में बदलना। फोरएच को उचित ठहराया जा सकता है जब बड़ी संख्या में अंक और प्रदर्शन महत्वपूर्ण होता है। अन्यथा यह केवल अनावश्यक जटिलता है। साथ ही, थ्रेडिंग समस्याओं से बचने के लिए सरणी को तत्व निर्दिष्ट करने से पहले इस कोड को लॉक (दूरीअरे) की आवश्यकता होती है। – j0aqu1n

0

मैं अतीत में इस जैसे कार्य करने मिला है, और मुझे लगता है कि अधिक संख्या में संकट के संचालन के लिए अपने तत्काल प्रतिक्रिया "है वहाँ एक तेजी से या होना चाहिए ऐसा करने के लिए और अधिक कुशल तरीका "। एकमात्र अन्य दूरस्थ रूप से काम करने योग्य समाधान मैं सोच सकता हूं कि जोश हैश है और इस हैश को हैशसेट में रखें, फिर दूरी गणना करने से पहले हैशसेट जांचें। हालांकि, यह अंततः प्रदर्शन के लिए बदतर काम करेगा।

आप समाधान अच्छे हैं। जैसा कि j0aqu1n बताता है, आपको शायद संख्याओं को एक या दूसरे तरीके से क्रंच करना होगा, और इस मामले में आप कभी भी दो बार समान गणना नहीं कर रहे हैं।

यह देखना दिलचस्प होगा कि इसके लिए कोई अन्य समाधान है या नहीं।

0

मेरे लिए अच्छा लग रहा है, लेकिन क्या आपके पास कोई बग नहीं है?

प्रत्येक आंतरिक पुनरावृत्ति प्रत्येक पहली स्थिति को छोड़कर पिछले एक को लगभग पूरी तरह से ओवरराइट कर देगी। है ना?

distanceArray[otherPointIndex] में अन्य पॉइंट इंडेक्स currentPointIndex + 1 से pointsArray.Length - 1 तक मान प्राप्त करता है।
आपके उदाहरण में, यह [0-6] के बजाय [0-3] पर होगा।

+0

हाँ, मेरे पास एक बग था, लेकिन मुझे नहीं लगता कि यह वह था। याद रखें, मैं छह खंड प्राप्त करने के लिए 0-3 (अंक) पर हूं। आपके प्रश्न ने मुझे एहसास दिलाया कि मैं दूरी सरणी को गड़बड़ कर रहा था। इसे अपने स्वयं के incrementer की जरूरत है। धन्यवाद। – Stonetip

0

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

+0

मैं इसे बड़े डेटासेट के साथ आज़मा दूंगा जहां प्रभाव स्पष्ट होगा। मैं शर्त लगाऊंगा कि आप सही हैं। मजेदार कैसे मैंने शाब्दिक रूप से x^2 को गणित का अनुवाद किया। जैसा कि आपने सुझाव दिया था बस करने के बजाय। – Stonetip

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

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