2013-01-02 13 views
6

का उपयोग करता है आगे बढ़ने से कोड का उपयोग करना, मैं सफलतापूर्वक संख्या का एक संग्रह का निर्माण करने और सरणी में तत्वों की स्थिति शफ़ल करने में कामयाब रहे:कैसे Enumerable.OrderBy keySelector

var randomNumbers = Enumerable.Range(0, 100) 
        .OrderBy(x => Guid.NewGuid()); 

सब कुछ कार्यों ठीक है, लेकिन यह एक तरह से एक फेंक दिया है Enumerable.OrderBy को समझने की कोशिश करते समय मेरे कार्यों में स्पैनर। उदाहरण के लिए निम्नलिखित कोड डालें:

var pupils = new[] 
{ 
    new Person() { Name = "Alex", Age = 17 }, 
    new Person() { Name = "Jack", Age = 21 } 
}; 

var query = pupils.OrderBy(x => x.Age); 

यह मेरी समझ है कि मैं संपत्ति मैं क्रमित करना चाहते हैं गुजर रहा है और मुझे लगता है कि LINQ Comparer<T>.Default का उपयोग करेगा संग्रह ऑर्डर करने के लिए कैसे करता है, तो कोई स्पष्ट IComparer के लिए निर्दिष्ट किया जाता है निर्धारित करने के लिए दूसरा अधिभार। मैं वास्तव में यह देखने में असफल रहा कि सरणी को इस तरह से घुमाने के लिए इस उचित तर्क को कैसे लागू किया जा सकता है। तो LINQ कैसे मुझे इस तरह एक सरणी shuffle करने देता है?

+0

मैं यहां आपके प्रश्न को समझ नहीं पा रहा हूं। आपके उपर्युक्त उदाहरण में, आयु मानना ​​एक int है, 'क्वेरी' में आदेशित सूची होगी। तो, आपकी प्रारंभिक सरणी को सॉर्ट या शफल नहीं किया गया है। – ryadavilli

+0

मैंने पोस्ट अपडेट किया। मैं पहले कोड नमूने के बारे में बात कर रहा हूँ। –

+0

फिशर-येट्स को वास्तविक कोड में शफल करने का प्रयास करें .. तेज .. – nawfal

उत्तर

5

कैसे Enumerable.OrderBy keySelector का उपयोग करता है हो सकता है?

Enumerable.OrderBy<T> lazily रिटर्न - keySelector सीधे नहीं बुलाया जाता है। नतीजा IOrderedEnumerable<T> है जो गणना करते समय ऑर्डरिंग करेगा।

जब गणना की गई, प्रत्येक तत्व के लिए कुंजी चयनकर्ता को एक बार बुलाया जाता है। चाबियों का क्रम तत्वों के नए क्रम को परिभाषित करता है।

यहां एक निफ्टी sample implementation है।


तो कैसे LINQ मुझे इस तरह एक सरणी शफ़ल जाने करता है?

var randomNumbers = Enumerable 
    .Range(0, 100) 
    .OrderBy(x => Guid.NewGuid()); 

Guid.NewGuid प्रत्येक तत्व के लिए कहा जाता है। दूसरे तत्व के लिए कॉल पहले तत्व के लिए कॉल से अधिक या कम मान उत्पन्न कर सकता है।

randomNumbers एक IOrderedEnumerable<int> है जो प्रत्येक बार गणना किए जाने पर एक अलग आदेश उत्पन्न करता है। प्रत्येक बार randomNumbers की गणना प्रत्येक बार प्रति तत्व को एक बार कहा जाता है।

2

तो कैसे काम करता है?

निम्नलिखित क्वेरी Comparer<Guid>.Default तुलना के लिए उपयोग करता है।

.OrderBy(x => Guid.NewGuid()) 

के बाद से हर उत्पन्न GUID व्यावहारिक रूप से अद्वितीय है (जैसा कि आप OrderBy खंड अपने आप में पैदा कर रहे हैं), तो आपको विश्वास है कि आप यादृच्छिक क्रम (जो गलत समझ है) हो रही है।
यदि आप फिर से क्वेरी चलाते हैं तो आप फिर से देखेंगे (संभावित रूप से) shuffled परिणाम के रूप में GUID का नया सेट जेनरेट किया जाएगा।

यदि आप पूर्वनिर्धारित GUID का उपयोग करेंगे, तो आप ऑर्डर देखेंगे।

उदाहरण randomNumbers1 और randomNumbers2 नीचे में एक ही मान हैं।

var randomGuids = Enumerable.Range(0,10).Select (x => Guid.NewGuid()).ToArray(); 

var randomNumbers1 = Enumerable.Range(0, 10).OrderBy(x => randomGuids[x]); 

var randomNumbers2 = Enumerable.Range(0, 10).OrderBy(x => randomGuids[x]); 

मैं वास्तव में देखने के लिए कि यह कैसे उचित तर्क के किसी भी इस तरह से सरणी शफ़ल करने के लिए लागू किया जा सकता असफल।

आप शफल कर सकते हैं क्योंकि तत्वों के बीच कोई ऑर्डर नहीं है (GUID आपके उदाहरण में)। यदि आप ऑर्डर करने वाले तत्वों का उपयोग करते हैं, तो आपको शफ़ल किए जाने के बजाए ऑर्डर आउटपुट मिलेगा।

+0

अब आपने मुझे यह दिया है मुझे गहरी जानकारी चाहिए> :) –

+0

@Alex, प्रश्न को अपडेट करें – Tilak

3

आप .. (सरल व्यक्ति अपने Age द्वारा हल कर रहे हैं,) सुंदर कैसे समझ में इस तरह की उथल काम करता है के करीब हैं अपने दूसरे मामले में

pupils.OrderBy(x => x.Age); 

Comparer<int>.Default प्रयोग किया जाता है।

अपने पहले मामले में, Comparer<Guid>.Default प्रयोग किया जाता है।

अब यह कैसे काम करता है?

हर बार जब आप Guid.NewGuid() (संभवतः) एक अलग/मूल/गैर डुप्लिकेट Guid उत्पादित करते हैं।अब जब आप

var randomNumbers = Enumerable.Range(0, 100).OrderBy(x => Guid.NewGuid()); 

संख्याएं उत्पन्न ग्रिड के आधार पर क्रमबद्ध की जाती हैं।

अब guids क्या हैं?

वे 128 बिट पूर्णांक हेक्साडेसिमल रूप में दर्शाए जाते हैं। चूंकि 2^128 इतनी बड़ी संख्या है कि दो गिड्स उत्पन्न करने की संभावना बहुत दुर्लभ/लगभग असंभव है। चूंकि गइड्स कुछ प्रकार की यादृच्छिकता प्रदर्शित करते हैं, इसलिए आदेश भी यादृच्छिक होगा।

आदेश देने के लिए दो गुड्स कैसे तुलना किए जाते हैं?

आप इसे एक छोटे प्रयोग के आधार पर पुष्टि कर सकते हैं। कार्य करें:

var guids = Enumerable.Range(0, 10).Select((x, i) => 
    { 
     Guid guid = Guid.NewGuid(); 
     return new { Guid = guid, NumberRepresentation = new BigInteger(guid.ToByteArray()), OriginalIndex = i }; 
    }).ToArray(); 

var guidsOrderedByTheirNumberRepresentation = guids.OrderBy(x => x.NumberRepresentation).ToArray(); 
var guidsOrderedAsString = guids.OrderBy(x => x.Guid.ToString()).ToArray(); 

var randomNumbers = Enumerable.Range(0, 10).OrderBy(x => guids[x].Guid).ToArray(); 

//print randomNumbers.SequenceEqual(guidsOrderedByTheirNumberRepresentation.Select(x => x.OriginalIndex)) => false 

//print randomNumbers.SequenceEqual(guidsOrderedAsString.Select(x => x.OriginalIndex)) => true 

तो Comparer<Guid>.Default GUID की स्ट्रिंग प्रतिनिधित्व पर आधारित है।


एक तरफ

:

Fisher-Yates गति के लिए फेरबदल

आप का उपयोग करना चाहिए। हो सकता है

public static IEnumerable<T> Shuffle<T>(this IList<T> lst) 
{ 
    Random rnd = new Random(); 
    for (int i = lst.Count - 1; i >= 0; i--) 
    { 
     int j = rnd.Next(i + 1); 
     yield return lst[j]; 
     lst[j] = lst[i]; 
    } 
} 

या संक्षिप्तता के लिए, बस (जो अभी भी Guid दृष्टिकोण की तुलना में तेजी हो सकता है)

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> lst) 
{ 
    Random rnd = new Random(); 
    return lst.OrderBy(x => rnd.Next()); 
}