2010-10-22 7 views
6

जब मेरे पास 2 List<string> ऑब्जेक्ट्स हैं, तो मैं और Except का उपयोग सीधे आउटपुट IEnumerable<string> प्राप्त करने के लिए कर सकता हूं। यह काफी आसान है, लेकिन अगर मैं कुछ जटिल पर छेड़छाड़/विघटन करना चाहता हूं तो क्या होगा?ऑब्जेक्ट्स के लिए LINQ का उपयोग करना और एक विशिष्ट संपत्ति को छोड़कर

उदाहरण के लिए, ClassA वस्तुओं, जिस पर एक दूसरे को काटना का परिणाम है का एक संग्रह प्राप्त करने की कोशिश ClassA वस्तु की AStr1 और ClassB वस्तु की BStr; :

public class ClassA { 
    public string AStr1 { get; set; } 
    public string AStr2 { get; set; } 
    public int AInt { get; set; } 
} 
public class ClassB { 
    public string BStr { get; set; } 
    public int BInt { get; set; } 
} 
public class Whatever { 
    public void xyz(List<ClassA> aObj, List<ClassB> bObj) { 
     // *** this line is horribly incorrect *** 
     IEnumberable<ClassA> result = 
      aObj.Intersect(bObj).Where(a, b => a.AStr1 == b.BStr); 
    } 
} 

मैं इस चौराहे को प्राप्त करने के लिए नोटलाइन लाइन को कैसे ठीक कर सकता हूं।

उत्तर

11

MoreLINQExceptBy है। यह अभी तक IntersectBy नहीं है, लेकिन आप आसानी से अपने खुद के कार्यान्वयन लिख सकता है, और संभवतः MoreLINQ करने के लिए इसे बाद में योगदान :)

यह शायद कुछ इस तरह (छोड़ते हुए त्रुटि जाँच) दिखेगा:

public static IEnumerable<TSource> IntersectBy<TSource, TKey>(
    this IEnumerable<TSource> first, 
    IEnumerable<TSource> second, 
    Func<TSource, TKey> keySelector, 
    IEqualityComparer<TKey> keyComparer) 
{ 
    HashSet<TKey> keys = new HashSet<TKey>(first.Select(keySelector), 
              keyComparer); 
    foreach (var element in second) 
    { 
     TKey key = keySelector(element); 
     // Remove the key so we only yield once 
     if (keys.Remove(key)) 
     { 
      yield return element; 
     } 
    } 
} 

यदि आप एक सामान्य संपत्ति प्रकार के दो अलग-अलग प्रकारों पर एक छेड़छाड़ करना चाहते हैं, तो आप तीन प्रकार के पैरामीटर (first के लिए एक, second के लिए एक और सामान्य कुंजी के लिए एक और सामान्य विधि बना सकते हैं) प्रकार)।

+0

हाय @Jon स्कीट, मुझे समझ नहीं आता कि कैसे मैं चौथे पैरामीटर पारित कर सकते हैं:

public IEnumerable<ClassA> xyz(List<ClassA> aObj, List<ClassB> bObj) { IEnumerable<string> bStrs = bObj.Select(b => b.BStr).Distinct(); return aObj.Join(bStrs, a => a.AStr1, b => b, (a, b) => a); } 

निम्नलिखित परीक्षा उत्तीर्ण की है। क्या मैं IEqualityComparer को लागू करके कक्षा को परिभाषित करता हूं और फिर इस कक्षा का एक उदाहरण पास करता हूं? – corei11

+0

@ corei11: हाँ, अगर आपको कुछ कस्टम चाहिए - या 'समानता कॉम्पैयर का उपयोग करें। डीफॉल्ट' यदि आप डिफ़ॉल्ट समानता संचालन से खुश हैं। –

+0

धन्यवाद @ जोन स्कीट। यहां मेरे पास दो 'आईनेमरेबल स्वामी 1' और 'owner2' है। और मैं 'IEqualityComparer' को लागू करके 'कंपार' नाम की एक कक्षा को परिभाषित करता हूं। अब विधि को 'owner1 = owner1.IntersectBy (owner2, item => item.Email_Address, नया तुलना ()) विधि से कॉल करें। दरअसल मैं यह स्पष्ट करना चाहता हूं कि मेरे कंपार वर्ग को कैसे पास किया जाए। यह सीधे मैं स्ट्रिंग लिखता हूं या कोई अन्य बेहतर तरीका या धन मेरे दृष्टिकोण ठीक है? मेरा कंपर क्लास प्रोटोटाइप 'पब्लिक क्लास कंपार है: आईक्वालिटी कॉम्पैयर '। माफ़ कीजिये। यह एक मूर्ख सवाल हो सकता है। धन्यवाद। – corei11

3

एक्स ∈ ए ∩ बी यदि और केवल यदि एक्स ∈ एक और एक्स ∈ बी

तो, aObj में प्रत्येक a के लिए, आप देख सकते हैं कि a.AStr1BStr मूल्यों के दस्तावेज़ में है।

public void xyz(List<ClassA> aObj, List<ClassB> bObj) 
{ 
    HashSet<string> bstr = new HashSet<string>(bObj.Select(b => b.BStr)); 
    IEnumerable<ClassA> result = aObj.Where(a => bstr.Contains(a.AStr1)); 
} 
1

इस कोड:

[TestMethod] 
    public void PropertyIntersectionBasedJoin() 
    { 
     List<ClassA> aObj = new List<ClassA>() 
           { 
            new ClassA() { AStr1 = "a" }, 
            new ClassA() { AStr1 = "b" }, 
            new ClassA() { AStr1 = "c" } 
           }; 
     List<ClassB> bObj = new List<ClassB>() 
           { 
            new ClassB() { BStr = "b" }, 
            new ClassB() { BStr = "b" }, 
            new ClassB() { BStr = "c" }, 
            new ClassB() { BStr = "d" } 
           }; 

     var result = xyz(aObj, bObj); 

     Assert.AreEqual(2, result.Count()); 
     Assert.IsFalse(result.Any(a => a.AStr1 == "a")); 
     Assert.IsTrue(result.Any(a => a.AStr1 == "b")); 
     Assert.IsTrue(result.Any(a => a.AStr1 == "c")); 
    } 
संबंधित मुद्दे