2009-03-24 17 views
44

मुझे कुछ प्रतिक्रिया चाहिए कि हम एक सामान्य कार्य कैसे लिख सकते हैं जो दो सूचियों की तुलना करने में सक्षम होगा। सूची में वर्ग वस्तुएं होती हैं और हम एक सूची के माध्यम से फिर से शुरू करना चाहते हैं, एक ही आइटम को दूसरी सूची में ढूंढना और किसी भी अंतर की रिपोर्ट करना चाहते हैं।मतभेदों के लिए दो सूचियों की तुलना करें

हमारे पास कक्षाओं की तुलना करने के लिए पहले से ही एक तरीका है, इसलिए हमें दो सूचियों से विधि (नीचे दिखाया गया) कैसे फ़ीड कर सकते हैं इस पर प्रतिक्रिया की आवश्यकता है।

उदाहरण के लिए, हमारे पास एक सरल "कर्मचारी" वर्ग है जिसमें तीन गुण, नाम, आईडी, विभाग हैं। हम सूची और दूसरी सूची के बीच मतभेदों की रिपोर्ट करना चाहते हैं।

नोट:
दोनों सूचियों में हमेशा समान संख्या में आइटम होंगे।

जैसा ऊपर बताया गया है, हमारे पास एक सामान्य विधि है जिसका उपयोग हम दो वर्गों की तुलना करने के लिए करते हैं, हम सूची को पूरा करने के लिए इस विधि को कैसे शामिल कर सकते हैं, यानी सूची के माध्यम से लूप और कक्षाओं को जेनेरिक विधि में फ़ीड करें। ... लेकिन हम नीचे दी गई विधि को पास करने के लिए दूसरी सूची में समकक्ष वर्ग कैसे प्राप्त करते हैं;

public static string CompareTwoClass_ReturnDifferences<T1, T2>(T1 Orig, T2 Dest) 
    where T1 : class 
    where T2 : class 
{ 
    // Instantiate if necessary 
    if (Dest == null) throw new ArgumentNullException("Dest", "Destination class must first be instantiated."); 

    var Differences = CoreFormat.StringNoCharacters; 

    // Loop through each property in the destination 
    foreach (var DestProp in Dest.GetType().GetProperties()) 
    { 
     // Find the matching property in the Orig class and compare 
     foreach (var OrigProp in Orig.GetType().GetProperties()) 
     { 

      if (OrigProp.Name != DestProp.Name || OrigProp.PropertyType != DestProp.PropertyType) continue; 
      if (OrigProp.GetValue(Orig, null).ToString() != DestProp.GetValue(Dest, null).ToString()) 
       Differences = Differences == CoreFormat.StringNoCharacters 
        ? string.Format("{0}: {1} -> {2}", OrigProp.Name, 
                 OrigProp.GetValue(Orig, null), 
                 DestProp.GetValue(Dest, null)) 
        : string.Format("{0} {1}{2}: {3} -> {4}", Differences, 
                   Environment.NewLine, 
                   OrigProp.Name, 
                   OrigProp.GetValue(Orig, null), 
                   DestProp.GetValue(Dest, null)); 
     } 
    } 
    return Differences; 
} 

कोई सुझाव या विचारों की सराहना की?

संपादित करें: .NET 2.0 को लक्षित करना LINQ प्रश्न से बाहर है।

+0

lol ... कोई, किसी उच्च स्तरीय, सिस्टम के महत्वपूर्ण आवेदन :-) गंभीरता से, एक छोटे से शौक एप्लिकेशन में इस कार्यक्षमता ... अपने सभी सीखने को लागू करने की कोशिश कर रहा। –

+0

बराबर लंबाई की सूचियां हैं? – Noldorin

+0

हाँ, सूचियां बराबर लंबाई –

उत्तर

15

.... लेकिन हम विधि विधि को पास करने के लिए दूसरी सूची में समकक्ष वर्ग कैसे प्राप्त करते हैं;

यह आपकी वास्तविक समस्या है; दोनों सूचियों में संबंधित वस्तुओं की पहचान करने के लिए आपके पास कम से कम एक अपरिवर्तनीय संपत्ति, एक आईडी या ऐसा कुछ होना चाहिए। यदि आपके पास ऐसी कोई संपत्ति नहीं है, तो त्रुटियों के बिना समस्या का समाधान नहीं कर सकते हैं। आप न्यूनतम या तार्किक परिवर्तनों की खोज करके संबंधित वस्तुओं को अनुमान लगाने का प्रयास कर सकते हैं।

यदि आपके पास ऐसी कोई संपत्ति है, तो समाधान वास्तव में सरल हो जाता है।

Enumerable.Join(
    listA, listB, 
    a => a.Id, b => b.Id, 
    (a, b) => CompareTwoClass_ReturnDifferences(a, b)) 

आप करने के लिए धन्यवाद दोनों danbruc और Noldorin आपकी प्रतिक्रिया के लिए। दोनों सूचियां लंबाई और उसी क्रम में समान होंगी। तो उपरोक्त विधि करीब है, लेकिन क्या आप इस विधि को enum पास करने के लिए संशोधित कर सकते हैं। ऊपर दी गई विधि के लिए वर्तमान?

अब मैं उलझन में हूं ... इसके साथ क्या समस्या है? क्यों न सिर्फ निम्नलिखित?

for (Int32 i = 0; i < Math.Min(listA.Count, listB.Count); i++) 
{ 
    yield return CompareTwoClass_ReturnDifferences(listA[i], listB[i]); 
} 

समान लंबाई की गारंटी होने पर Math.Min() कॉल को भी छोड़ा जा सकता है।


Noldorin के कार्यान्वयन प्रतिनिधि और बदले ICollection का उपयोग करने का प्रगणक के प्रयोग की वजह होशियार निश्चित रूप से है।

+0

ठीक देखें, मान लीजिए कि कर्मचारी.आईडी कभी नहीं बदलेगा। –

+0

क्षमा करें, हम .NET 2.0 को लक्षित कर रहे हैं। मुझे यह मुद्दा बनाना चाहिए था। –

+0

LINQ * * .NET 2.0 पर चला सकता है। Http://code.google.com/p/linqbridge/ –

6

मुझे लगता है कि आप इस तरह से एक विधि के लिए देख रहे:

public static IEnumerable<TResult> CompareSequences<T1, T2, TResult>(IEnumerable<T1> seq1, 
    IEnumerable<T2> seq2, Func<T1, T2, TResult> comparer) 
{ 
    var enum1 = seq1.GetEnumerator(); 
    var enum2 = seq2.GetEnumerator(); 

    while (enum1.MoveNext() && enum2.MoveNext()) 
    { 
     yield return comparer(enum1.Current, enum2.Current); 
    } 
} 

यह untested है, लेकिन यह काम भी करना चाहिए। ध्यान दें कि इस विधि के बारे में विशेष रूप से उपयोगी क्या है कि यह पूर्ण सामान्य है, यानी यह मनमानी (और अलग) प्रकारों के दो अनुक्रम और किसी भी प्रकार की वस्तुओं को वापस ले सकता है।

पाठ्यक्रम का यह समाधान मानता है कि आप में nth आइटम के साथ seq1 की nth आइटम की तुलना करना चाहते हैं। यदि आप किसी विशेष संपत्ति/तुलना के आधार पर दो अनुक्रमों में तत्वों से मेल खाना चाहते हैं, तो आप join ऑपरेशन का कुछ प्रकार करना चाहते हैं (जैसा कि Enumerable.Join का उपयोग करके डैनब्रुक द्वारा सुझाया गया है। अगर मुझे इनमें से कोई भी दृष्टिकोण नहीं है तो मुझे बताएं काफी है कि मैं क्या कर रहा हूँ के बाद और शायद मैं कुछ और कर सकते हैं सुझाव

संपादित करें:।। का तरीका यहां बताया comparer समारोह आप मूल रूप से तैनात साथ उपयोग कर सकते हैं CompareSequences विधि का एक उदाहरण है

// Prints out to the console all the results returned by the comparer function (CompareTwoClass_ReturnDifferences in this case). 
var results = CompareSequences(list1, list2, CompareTwoClass_ReturnDifferences); 
int index;  

foreach(var element in results) 
{ 
    Console.WriteLine("{0:#000} {1}", index++, element.ToString()); 
} 
+0

देखें यह दोनों सूचियों को सिंक्रनाइज़ेशन से चलाएगा लेकिन ऑब्जेक्ट को दोनों सूचियों में उसी तरह से आदेश नहीं दिया जा सकता है। –

+0

हां, ज़ाहिर है।मैं इस सवाल से काफी नहीं इकट्ठा नहीं कर सकता था कि यह मामला था या नहीं, लेकिन फिर भी मैं आपकी टिप्पणी पढ़ने से पहले ही पोस्ट संपादित करूँगा, इसलिए अब यह संपत्ति योग्य है ... – Noldorin

+0

आपके लिए डैनब्रुक और नोल्डोरिन दोनों के लिए धन्यवाद प्रतिक्रिया। दोनों सूचियां समान लंबाई और उसी क्रम में होंगी। तो उपर्युक्त विधि करीब है, लेकिन क्या आप इस विधि को enum पास करने के लिए संशोधित कर सकते हैं। ऊपर पोस्ट की गई विधि के लिए वर्तमान? –

1

मुझे आशा है कि मैं आपके प्रश्न को सही तरीके से समझ रहा हूं, लेकिन आप यह कर सकते हैं लिंक के साथ जल्दी से आरई। मुझे लगता है कि सार्वभौमिक रूप से आपके पास हमेशा एक आईडी संपत्ति होगी। यह सुनिश्चित करने के लिए बस एक इंटरफ़ेस बनाएं।

यदि कक्षा से कक्षा में समान परिवर्तन होने के लिए आप किसी ऑब्जेक्ट की पहचान कैसे करते हैं, तो मैं एक ऐसे प्रतिनिधि में गुजरने की अनुशंसा करता हूं जो दो वस्तुओं के समान निरंतर आईडी हो।

यहाँ कैसे Linq में यह करने के लिए है:

List<Employee> listA = new List<Employee>(); 
     List<Employee> listB = new List<Employee>(); 

     listA.Add(new Employee() { Id = 1, Name = "Bill" }); 
     listA.Add(new Employee() { Id = 2, Name = "Ted" }); 

     listB.Add(new Employee() { Id = 1, Name = "Bill Sr." }); 
     listB.Add(new Employee() { Id = 3, Name = "Jim" }); 

     var identicalQuery = from employeeA in listA 
          join employeeB in listB on employeeA.Id equals employeeB.Id 
          select new { EmployeeA = employeeA, EmployeeB = employeeB }; 

     foreach (var queryResult in identicalQuery) 
     { 
      Console.WriteLine(queryResult.EmployeeA.Name); 
      Console.WriteLine(queryResult.EmployeeB.Name); 
     } 
+0

-1 आईडी की तुलना करना पर्याप्त नहीं है। – aggietech

72

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

var DifferencesList = ListA.Where(x => !ListB.Any(x1 => x1.id == x.id)) 
      .Union(ListB.Where(x => !ListA.Any(x1 => x1.id == x.id))); 
+6

यह बहुत अच्छा है। समुदाय वास्तव में आपको किसी अन्य व्यक्ति को किसी समस्या पर देखने की अनुमति देते हैं। धन्यवाद! – Jeremy

+1

सही काम करता है! धन्यवाद – Haris

+0

मेरा मानना ​​है कि यह मानता है कि सूची में कोई डुप्लिकेट नहीं है? – NStuke

2

Microsoft से यह दृष्टिकोण बहुत अच्छी तरह से काम करता है और एक से दूसरे सूची की तुलना और प्रत्येक में अंतर पाने के लिए उन्हें स्विच करने का विकल्प प्रदान करता है। यदि आप कक्षाओं की तुलना कर रहे हैं तो बस अपनी ऑब्जेक्ट्स को दो अलग-अलग सूचियों में जोड़ें और फिर तुलना करें।

http://msdn.microsoft.com/en-us/library/bb397894.aspx

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