2010-08-04 14 views
5

में मनमानी रैंक के सरणी में अनुक्रमण करना मुझे मनमाना रैंक की एक सरणी पर फिर से चलने की आवश्यकता है। यह पढ़ने और लिखने दोनों के लिए है, इसलिए GetEnumerator काम नहीं करेगा।सी #

Array.SetValue(object, int) बहुआयामी सरणी पर काम नहीं करता है। Array.SetValue(object, params int[]) को बहुआयामी अंतरिक्ष के माध्यम से पुनरावृत्ति के लिए अत्यधिक अंकगणित की आवश्यकता होगी। हस्ताक्षर के params भाग के लिए इसे गतिशील आमंत्रण की भी आवश्यकता होगी।

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

क्या केवल एक ही इंडेक्स का उपयोग करके एक बहुआयामी सरणी को अनुक्रमिक रूप से संबोधित करने का कोई आसान तरीका है?

+2

मुझे "असुरक्षित" कोड का उपयोग करने में कोई त्रुटि नहीं दिखाई देती है। पॉइंटर्स का उपयोग करना सुरक्षित है जब आप वास्तव में जानते हैं कि आप क्या कर रहे हैं और यह एक व्यवहार्य और कुशल समाधान है। –

+2

बीटीडब्ल्यू यह 'int []' पास करने के लिए पूरी तरह से मान्य है जहां 'पैराम int [] 'अपेक्षित है। – dtb

+0

@ डीटीबी, आप दोनों वाक्यविन्यास बिंदुओं पर सही प्रतीत होते हैं। मुझे कभी नहीं पता था कि आप सीधे एक सरणी पैरामीटर सरणी पैरामीटर में पास कर सकते हैं। –

उत्तर

5

बहुआयामी सरणी संगत होने की गारंटी है। ECMA-335 से:

सरणी तत्वों पंक्ति-प्रमुख क्रम में सरणी वस्तु के भीतर बाहर रखी किया जाएगा (यानी, सबसे दायीं ओर सरणी आयाम के साथ जुड़े तत्वों की सबसे कम करने के लिए उच्चतम सूचकांक से रखी किया जाएगा समीपवर्ती) ।

तो यह काम करता है:

int[,,,] array = new int[10, 10, 10, 10]; 

fixed (int* ptr = array) 
{ 
    ptr[10] = 42; 
} 

int result = array[0, 0, 1, 0]; // == 42 
+0

धन्यवाद, यही वह है जिसे मैं ढूंढ रहा था और मुझे एक अच्छा गिरावट का कार्यान्वयन देता है। बीटीडब्ल्यू, मुझे लगता है कि आपका कोड 'int * ptr = array' पर चोक करता है, लेकिन विचार ध्वनि है। –

+0

@ केनेट बेलेन्की: मैंने अभी दो बार जांच की है और कोड पूरी तरह से काम करता है। बेशक, असुरक्षित कोड से जुड़े समाधान में मदद नहीं मिलती है अगर आप असुरक्षित कोड से बचना चाहते हैं, लेकिन मुझे डर है कि कोई अन्य समाधान नहीं है जो बहुत से (अनावश्यक) ओवरहेड (जैसे सभी आयामों के माध्यम से पुनरावर्तक रूप से पुनरावृत्त) के साथ नहीं आता है। । – dtb

+0

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

-1

शायद आप उन सभी को एक ही अस्थायी संग्रह में शामिल कर सकते हैं, और बस उस पर फिर से शुरू हो सकते हैं।

+0

काफी आसान है, मैं केवल सरणी में सबकुछ संबोधित करने के लिए GetEnumerator का उपयोग करूंगा। समस्या यह है कि मुझे सरणी में विभिन्न बिंदुओं पर भी लिखना है, और इसके लिए GetEnumerator विफल हो जाएगा। –

1

आप Rank और GetUpperBound संपत्ति/विधि का उपयोग एक सूचकांक सरणी है कि आप सरणी के SetValue और GetValue तरीकों को पारित कर सकते हैं बनाने के लिए कर सकते हैं:

int[] Indices(Array a, int idx) 
{ 
    var indices = new int[a.Rank]; 

    for (var i = 0; i < a.Rank; i++) 
    { 
     var div = 1; 

     for (var j = i + 1; j < a.Rank; j++) 
     { 
      div *= a.GetLength(j); 
     } 

     indices[i] = a.GetLowerBound(i) + idx/div % a.GetLength(i); 
    } 

    return indices; 
} 

.. और इसका उपयोग इस प्रकार करें:

for (var i = 0; i < array.Length; i++) 
{ 
    var indices = Indices(array, i); 
    array.SetValue(i, indices); 
    var val = array.GetValue(indices); 
} 
+1

हां, यह अत्यधिक अंकगणित होगा जिसके बारे में मैं बात कर रहा था। आपको ऐरे का उपयोग करने की भी आवश्यकता होगी। गेटलोवरबाउंड, न सिर्फ ऐरे। गेटअपपरबाउंड। –

+0

आप बिल्कुल सही हैं, इसे सही कोड में डाल दें, क्षमा करें। –

+0

@ केनेट वास्तव में, हमें * Array.GetUpperBound' की आवश्यकता नहीं है, बस 'Array.GetLength' विधि देखी गई :) –