2012-04-27 12 views
8

मैं किसी अज्ञात ऑब्जेक्ट के साथ काम करने के लिए LINQ कथन में OrderBy प्राप्त करने का प्रयास कर रहा हूं लेकिन अब तक विफल रहा है।LINQ आदेश प्रक्षेपण तुलनाकर्ता के साथ अज्ञात ऑब्जेक्ट

मैं इन पहले ही जाँच:
Anonymous IComparer implementation
C# linq sort - quick way of instantiating IComparer
How to sort an array of object by a specific field in C#?

मैं अलग दृष्टिकोण की कोशिश कर रहा में कुछ घंटे बिताए लेकिन वहाँ कुछ मैं याद कर रहा हूँ हो गया है।

के वहाँ निम्नलिखित वर्ग का कहना है कि दो:

public class Product 
{ 
    public int Id {get; set;} 
    public string Name {get; set;} 
    public int Popularity {get; set;} 
    public decimal Price {get; set;} 
} 

और products इन वस्तुओं की एक सूची है।

मैं इस LINQ कथन को कैसे पूरा कर सकता हूं, ताकि यह अज्ञात ऑब्जेक्ट के साथ काम कर सके?
स्पष्ट होने के लिए, मुझे पता है कि मैं इसे एक अलग तरीके से कर सकता हूं लेकिन मुझे यह जानने में बहुत दिलचस्पी होगी कि यह विशेष उदाहरण कैसे काम करें।

var sortedProducts = products 
         .OrderBy(p => 
           new {p.Popularity, p.Price}, 
           [IComparer magic goes here]); 

ऐसा लगता है कि यह ProjectionComparer के एक कार्यान्वयन के साथ संभव हो जाना चाहिए:
http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be

कोई भी विचार कैसे यह करने के लिए?

अद्यतन:

मैं इस पर एक त्वरित प्रदर्शन परीक्षण किया - गुमनाम comparer समाधान बनाम मानक orderby.thenby और ऐसा लगता है कि गुमनाम समाधान काफी धीमी है जो शायद है कि हम क्या वैसे भी उम्मीद हो सकता है।

  numProd | Anon | chained orderby clauses 
     10 000 | 47 ms | 31 ms 
     100 000 | 468 ms | 234 ms 
     1 000 000| 5818 ms | 2387 ms 
     5 000 000| 29547 ms| 12105 ms 
+0

आपके ऑर्डरिंग मानदंड क्या हैं? क्या आप कह रहे हैं कि यह लोकप्रियता पहले होनी चाहिए, फिर कीमत से? लोकप्रियता पर ऑर्डरबी क्यों नहीं करें और फिर कीमत पर क्यों? –

+0

@JamesMichaelHare - चलिए एक प्राथमिक कारक के रूप में उच्च लोकप्रियता कहते हैं, उदाहरण के लिए इससे कोई फर्क पड़ता है, तो द्वितीयक कारक के रूप में कम कीमत। संपादित करें: मुझे पता है कि मैं यह कर सकता हूं लेकिन मुझे आश्चर्य है कि अनाम वस्तु के साथ दृष्टिकोण बिल्कुल काम करेगा, और यदि ऐसा है, तो मैं बस यह नहीं समझ सकता कि कैसे। –

+1

ऑर्डरबी() में किसी अज्ञात ऑब्जेक्ट का उपयोग क्यों करें? क्यों न केवल: 'products.OrderByDescending (p => p.Popularity) .henby (p => p.Price) ' –

उत्तर

7

आप एक IComparer<T> कार्यान्वयन एक प्रतिनिधि है कि आप तुलना के लिए आपूर्ति का उपयोग करता है बना सकते हैं, और प्रकार निष्कर्ष के साथ यह दृष्टांत (समान "उदाहरण के द्वारा डाली" के लिए):

static class AnonymousComparer 
{ 
    public static IComparer<T> GetComparer<T>(T example, Comparison<T> comparison) 
    { 
     return new ComparerImpl<T>(comparison); 
    } 
    private class ComparerImpl<T> : IComparer<T> 
    { 
     private readonly Comparison<T> _comparison; 
     public ComparerImpl(Comparison<T> comparison) { _comparison = comparison; } 
     public int Compare(T x, T y) { return _comparison.Invoke(x, y); } 
    } 
} 

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

var comparer = AnonymousComparer.GetComparer(
    new { Popularity = 0, Price = 0m }, 
    (a, b) => //comparison logic goes here 
    ); 

var sortedProducts = products 
    .OrderBy(p => 
     new { p.Popularity, p.Price }, 
     comparer); 

संपादित करें: मैं बस प्रक्षेपण comparer पेज से लिंक की जाँच की। उस दृष्टिकोण के साथ, आपको टाइप अनुमान के लिए "उदाहरण" तर्क की आवश्यकता नहीं है। हालांकि, इंटरफ़ेस के बजाय प्रतिनिधि को लेने के लिए अभी भी दृष्टिकोण को अनुकूलित करने की आवश्यकता है। यहां यह है:

//adapted from http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be 
static class AnonymousProjectionComparer 
{ 
    private class ProjectionComparer<TElement, TKey> : IComparer<TElement> 
    { 
     private readonly Func<TElement, TKey> keySelector; 
     private readonly Comparison<TKey> comparison; 

     internal ProjectionComparer(Func<TElement, TKey> keySelector, Comparison<TKey> comparison) 
     { 
      this.keySelector = keySelector; 
      this.comparison = comparison ?? Comparer<TKey>.Default.Compare; 
     } 

     public int Compare(TElement x, TElement y) 
     { 
      TKey keyX = keySelector(x); 
      TKey keyY = keySelector(y); 
      return comparison.Invoke(keyX, keyY); 
     } 
    } 

    public static IComparer<TElement> GetComparer<TElement, TKey>(Func<TElement, TKey> keySelector, Comparison<TKey> comparison) 
    { 
     return new ProjectionComparer<TElement, TKey>(keySelector, comparison); 
    } 
} 
+0

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

4

आप वास्तव में एक गुमनाम वस्तु की जरूरत नहीं है populartiy उतरते और फिर कीमत द्वारा इन वस्तुओं ऑर्डर करने के लिए, आप संयोजन में OrerBy और ThenBy उपयोग कर सकते हैं, जैसे:

var sortedProducts = products.OrderByDescending(p => p.Popularity) 
    .ThenBy(p => p.Price); 

पर एक IComparer<T> ऐसा करने के लिए एक अनाम प्रकार, आप एक प्रतिनिधि से एक बनाने के लिए कारखाने का उपयोग करना बंद कर देंगे और टाइप अनुमान (उपयोग के बिना अनाम प्रकार निर्दिष्ट करना दर्द है!)।

आप विशुद्ध रूप से आदेश देने के लिए गुमनाम वस्तुओं बनाने के प्रदर्शन निहितार्थ को मापने के लिए चाहते हो सकता है, लेकिन Phoogs जवाब मक्खी पर एक IComparer<T> के निर्माण के लिए Comparison<T> प्रतिनिधि का उपयोग करने के लिए एक अच्छा तरीका देता है ..

+0

ऊपर देखें - अगर यह छोटा था तो मुझे उम्मीद थी कि मैं बिना मदद के इसे कर पाऊंगा। मुझे पता है कि समस्या को अलग तरीके से हल किया जा सकता है। –

+0

@ जोना: समझा, बस यह सुनिश्चित करना चाहता था कि यह जानने का कोई मुद्दा नहीं था कि ऑर्डरबी/फिर से बंधे जा सकते हैं। Phoog नीचे एक अच्छा समाधान है। –

+0

मैंने कुछ संक्षिप्त प्रदर्शन परीक्षण के परिणामों के साथ अद्यतन किया - अज्ञात तुलनात्मक समाधान अपेक्षा के अनुसार धीमा है। यह जानना अच्छा है। –

0

नहीं वास्तव में एक जवाब .. लेकिन टिप्पणी के लिए बहुत लंबा: समझदार जेनेरिक तुलनात्मक बनाना मुश्किल है।

हालांकि एकल संपत्ति द्वारा वस्तुओं के लिए अच्छी तरह से स्थापित तुलना संबंध है, वहां कई या यहां तक ​​कि 2 गुणों के लिए ऐसी कोई चीज़ नहीं है। अर्थात। जब आप सपाट सतह पर बिंदुओं को ऑर्डर करने का प्रयास करते हैं तो यह बहुत आम समस्या है: केवल 2 मान (x, y) लेकिन कहने का कोई तरीका नहीं है (x1, y1) < (x2, y2) ताकि सभी इससे सहमत हों।

ज्यादातर मामलों में आप विशेषता 1 के मुकाबले विशेषता 1 द्वारा ऑर्डर करते हैं, या सभी मानों को एकल मान में मैप करके (यानी बस उन सभी को गुणा करके)।इन तरीकों को आसानी से LINQ में जेनेरिक comparer की आवश्यकता के बिना व्यक्त कर रहे हैं: के साथ विशेषताओं द्वारा

  • आदेश श्रृंखलित OrderBy (ATTR1) .OrderBy (ATTR2) ....
  • आदेश मीट्रिक OrderBy (ATTR1 * ATTR2) द्वारा (या किसी अन्य Metric अपने वस्तुओं पर)
+1

जो मुझे रूचि है वह मूल रूप से इस चीज़ का कार्यान्वयन है: http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be। मुझे लगता है कि अगर मुझे यह अधिकार मिलता है तो बाकी काम करेंगे, लेकिन मुझे इसके साथ मदद की ज़रूरत होगी। –

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