2010-11-17 15 views
15

यह मानते हुए कि यह एक बहुत ही बुनियादी कार्य है, मैं इसे करने का एक उचित तरीका नहीं सोच सकता था। आप int सरणी में निम्नतम मान का सूचकांक कैसे प्राप्त करेंगे? लिंक/मोरलिंक का उपयोग करना संभव है। मुझे अब तक एक उचित लाइनर नहीं मिला।आप एक int सरणी में निम्नतम मूल्य का सूचकांक कैसे प्राप्त करेंगे?

+2

क्या सरणी में डुप्लिकेट संख्या हो सकती है, और इस मामले में, यदि आप निम्नतम संख्या में से दो हैं तो आप कौन सी अनुक्रमणिका दिखाना चाहते हैं ? – Paddy

+0

@Paddy हां डुप्लिकेट संभव है। इनमें से कोई भी वापस लौटने के लिए ठीक है, हालांकि एक (किसी भी) लगातार व्यवहार की सराहना की जाएगी (उदाहरण के लिए हमेशा अंतिम)। – mafu

उत्तर

17

जब से तुम MoreLinq, के बारे में कैसे उल्लेख:

int[] array = .. 

// Will throw if the array is empty. 
// If there are duplicate minimum values, the one with the smaller 
// index will be chosen. 
int minIndex = array.AsSmartEnumerable() 
        .MinBy(entry => entry.Value) 
        .Index; 

एक अन्य विकल्प:

// Will throw if the array is empty. 
// Requires two passes over the array. 
int minIndex = Array.IndexOf(array, array.Min()); 

आप निश्चित रूप से अपने खुद के विस्तार-विधि लिख सकते हैं:

// Returns last index of the value that is the minimum. 
public static int IndexOfMin(this IEnumerable<int> source) 
{ 
    if(source == null) 
    throw new ArgumentNullException("source"); 

    int minValue = int.MaxValue; 
    int minIndex = -1; 
    int index = -1; 

    foreach(int num in source) 
    { 
     index++; 

     if(num <= minValue) 
     { 
     minValue = num; 
     minIndex = index; 
     } 
    } 

    if(index == -1) 
    throw new InvalidOperationException("Sequence was empty"); 

    return minIndex; 
} 

कुछ प्रयास के साथ , आप IComparer<T> को स्वीकार कर किसी भी प्रकार से इसे सामान्यीकृत कर सकते हैं,पर डिफॉल्ट।

+0

आपने एक्सटेंशन विधि में फ़ोरैच क्यों चुना है? – mafu

+0

सामान्य रूप से, अनुक्रमों को अनुक्रम द्वारा एक्सेस नहीं किया जा सकता है। एक 'foreach' का उपयोग करना मनमाना अनुक्रम को फिर से शुरू करने का सामान्य तरीका है। आप * गणनाकर्ता प्राप्त कर सकते हैं और फिर 'लूप' का उपयोग कर सकते हैं, लेकिन यह काफी गन्दा दिखता है। यदि आपको वास्तव में गणनाकर्ता की आवश्यकता है, तो 'while' लूप कहीं अधिक आम है। इस मामले में, न तो आवश्यक है। – Ani

+0

ओह, हाँ, मैं गलती से 'स्रोत' के बारे में सोच रहा था। – mafu

4

बहुत स्मृति अनुकूल नहीं है, लेकिन ...

array.Select((n, i) => new { index = i, value = n }) 
    .OrderBy(item => item.value) 
    .First().index 
+0

आप ऑर्डरबी/फर्स्ट को मिनीबी के साथ भी बदल सकते हैं। – mafu

+1

@ mafutrct: हाँ यदि आपके पास MoreLinq है, जो आप करते हैं लेकिन मैं नहीं करता :) –

1

यह बदसूरत है, लेकिन यह केवल अनुक्रम के माध्यम से एक भी पास की जरूरत है और केवल का उपयोग करता है में निर्मित ढांचे तरीके:

int index = yourArray.Select((x, i) => new { Val = x, Idx = i }) 
        .Aggregate(new { Val = -1, Idx = -1 }, 
           (a, x) => (x.Idx == 0 || x.Val < a.Val) ? x : a, 
           x => x.Idx); 

और, जाहिर है, आप एक सामान्य प्रयोजन विस्तार विधि लिख सकते हैं:

int index = yourArray.MinIndex(); 

// ... 

public static class EnumerableExtensions 
{ 
    public static int MinIndex<T>(
     this IEnumerable<T> source, IComparer<T> comparer = null) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     if (comparer == null) 
      comparer = Comparer<T>.Default; 

     using (var enumerator = source.GetEnumerator()) 
     { 
      if (!enumerator.MoveNext()) 
       return -1; // or maybe throw InvalidOperationException 

      int minIndex = 0; 
      T minValue = enumerator.Current; 

      int index = 0; 
      while (enumerator.MoveNext()) 
      { 
       index++; 
       if (comparer.Compare(enumerator.Current, minValue) < 0) 
       { 
        minIndex = index; 
        minValue = enumerator.Current; 
       } 
      } 
      return minIndex; 
     } 
    } 
} 
8

LINQ शायद सबसे अच्छा समाधान च नहीं है या यह समस्या, लेकिन यहां एक और भिन्नता है जो ओ (एन) है। यह सॉर्ट नहीं करता है और केवल एक बार सरणी को घुमाता है।

var arr = new int[] { 3, 1, 0, 5 }; 
int pos = Enumerable.Range(0, arr.Length) 
    .Aggregate((a, b) => (arr[a] < arr[b]) ? a : b); // returns 2 

अद्यतन: मूल प्रश्न सीधे उत्तर देना, यह कैसे मैं यह कर देगी:

var arr = new int[] { 3, 1, 0, 5 }; 
int pos = 0; 
for (int i = 0; i < arr.Length; i++) 
{ 
    if (arr[i] < arr[pos]) { pos = i; } 
} 
// pos == 2 

नहीं, यह LINQ का उपयोग नहीं करता। हां, यह एक से अधिक पंक्ति है। लेकिन यह वास्तव में सरल और वास्तव में तेज़ है। इसे एक छोटी सी छोटी विधि में बनाएं और इसे किसी भी पंक्ति से कहीं भी कॉल करें: pos = FindMinIndex(arr);

+0

यह उत्तर होना चाहिए। बहुत तेज और सरल! – RMalke

+0

@RMalke कितनी तेज़ी से? – shoelzer

+0

मुझे माप नहीं आया, लेकिन मुझे चयन किया गया था ((x, i) => ...) ऑर्डरबी (...)। पहला (...) और इसे सटीक समय 15257190400 पर कॉल करना। मैं टी काफी तेज़ था – RMalke

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