आप LINQ के साथ "नहीं" क्वेरी कैसे करेंगे?


307

मेरे पास दो संग्रह हैं जिनके पास Emailदोनों संग्रहों में संपत्ति है। मुझे पहली सूची में उन वस्तुओं की एक सूची प्राप्त करने की आवश्यकता है जहां Emailदूसरी सूची में मौजूद नहीं है। SQL के साथ मैं सिर्फ "नहीं" का उपयोग करूंगा, लेकिन मुझे LINQ में इसके समकक्ष नहीं पता है। कैसे किया जाता है?

अब तक मेरे पास एक जॉइन है, जैसे ...

var matches = from item1 in list1
join item2 in list2 on item1.Email equals item2.Email
select new { Email = list1.Email };

लेकिन मैं इसमें शामिल नहीं हो सकता क्योंकि मुझे अंतर की आवश्यकता है और जुड़ना विफल हो जाएगा। मुझे विश्वास है कि कंटेस्टेंट्स या एक्ज़िस्ट का उपयोग करने के कुछ तरीके चाहिए। मुझे अभी ऐसा करने के लिए एक उदाहरण नहीं मिला है।


3
कृपया ध्यान दें कि इकोस्टॉर्म का उत्तर कोड का उत्पादन करता है जो रॉबर्ट की तुलना में पढ़ने के लिए बहुत स्पष्ट है
नाथन कोप

जवाबों:


302

मुझे नहीं पता कि यह आपकी मदद करेगा लेकिन ..

NorthwindDataContext dc = new NorthwindDataContext();    
dc.Log = Console.Out;

var query =    
    from c in dc.Customers    
    where !(from o in dc.Orders    
            select o.CustomerID)    
           .Contains(c.CustomerID)    
    select c;

foreach (var c in query) Console.WriteLine( c );

से LINQ में नहीं खंड एसक्यूएल करने से मार्को रूसो


लेकिन मैं संस्थाओं के लिए linq का उपयोग करता हूं, इसलिए मुझे "केवल आदिम प्रकार का उपयोग किया जा सकता है त्रुटि"। क्या आसपास कोई काम है ...? मैन्युअल रूप से पुनरावृत्ति और सूची को खोजने के अलावा।
Novice

13
यह LINQ से लेकर Entities तक मेरे लिए ठीक काम करता है। SQL एक WHERE NOT EXISTS (सबक्वेरी) क्वेरी बन जाती है। शायद कोई अपडेट था जिसने इसे संबोधित किया था?
स्काउटचेल

2
मुझे लगता है कि EF के नए संस्करण समर्थन करते हैं। काम करता है, साथ ही यह सवाल EF (संस्करण) या LinqToSQL को टैग नहीं करता है .. इसलिए यहाँ प्रश्न और उत्तर को गुंजाइश की आवश्यकता हो सकती है ..
ब्रेट कैसवेल

4
@ रॉबर्ट राउज़ - लिनल इन क्लक टू लाइन इन लिंक टू सीक्यूएल अब काम नहीं करता। बस एक फी।
जॉन

लिंक प्रदान की गई साइट को मैलवेयर युक्त के रूप में चिह्नित किया गया है।
18:05

334

आप सिवाय ऑपरेटर को चाहते हैं।

var answer = list1.Except(list2);

यहाँ बेहतर व्याख्या: https://docs.microsoft.com/archive/blogs/charlie/linq-farm-more-on-set-operators

नोट: यह तकनीक केवल आदिम प्रकारों के लिए सबसे अच्छा काम करती है, क्योंकि आपको जटिल प्रकारों के साथ विधि का उपयोग करने के लिए IEqualityComparer लागू करना होगा Except


7
सिवाय का उपयोग करते हुए: यदि आप जटिल प्रकार की सूचियों के साथ काम करते हैं, तो आपको एक IEqualityComparer <MyComlplexType> को लागू करना होगा, जो इसे अच्छा नहीं बनाता है
sakito

4
यदि आप संदर्भ समानता की तुलना करना चाहते हैं या यदि आपने T.Equals () और T.GetHashCode () की तुलना करना चाहते हैं तो आपको IEqualityComparer <T> को लागू करने की आवश्यकता नहीं है । यदि आप IEqualityComparer <T> लागू नहीं करते हैं, तो EqualityComparer <T> .Default का उपयोग किया जाएगा।
पाइडर

2
@ इकोस्टॉर्म (और अन्य पढ़ने वाले), यदि आप सेलेक्ट टू बेनामी ऑब्जेक्ट करते हैं, तो हैशकोड संपत्ति मूल्यों द्वारा निर्धारित किया जाएगा; list1.Select(item => new { Property1 = item.Property1, Property2 = item.Property2 }).Except(list2.Select( item => new { Property1 = item.Property1, Property2 = item.Property2 }));यह तब विशेष रूप से उपयोगी है जब आप जटिल प्रकार के मूल्यों के एक सेट का मूल्यांकन करके समानता का निर्धारण कर रहे हैं।
ब्रेट कैसवेल

3
वास्तव में, किसी ने नीचे बताया, और मुझे सही ढंग से लगता है, कि IEquatityComparor<T,T>एक LinqToSqlपरिदृश्य में ऑब्जेक्ट तुलना विधियों को लागू करने या ओवरराइड करने की आवश्यकता नहीं होगी ; के लिए, क्वेरी को एसक्यूएल के रूप में / संकलित / व्यक्त किया जाएगा; इस प्रकार मूल्यों की जाँच की जाएगी, न कि वस्तु संदर्भ की।
ब्रेट कैसवेल

2
exceptमैं का उपयोग कर एक LINQ क्वेरी 8-10 सेकंड से आधे से एक सेकंड के लिए तेजी से करने में सक्षम था
माइकल नाइकेर्न

61

उन लोगों के लिए जो इन-मेमोरी ऑब्जेक्ट्स के समूह से शुरू करते हैं और एक डेटाबेस के खिलाफ क्वेरी कर रहे हैं, मैंने पाया है कि यह सबसे अच्छा तरीका है:

var itemIds = inMemoryList.Select(x => x.Id).ToArray();
var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));

यह WHERE ... IN (...)SQL में एक अच्छा क्लाज पैदा करता है ।


1
वास्तव में, आप ऐसा कर सकते हैं कि 3.5 में
जॉर्ज सिल्वा

59

पहली सूची में आइटम जहां दूसरी सूची में ईमेल मौजूद नहीं है।

from item1 in List1
where !(list2.Any(item2 => item2.Email == item1.Email))
select item1;

16

आप कहां और कहां नहीं मिल सकते हैं, इसके संयोजन का उपयोग कर सकते हैं:

var NotInRecord =list1.Where(p => !list2.Any(p2 => p2.Email  == p.Email));

8

आप दो अलग-अलग सूचियों में दोनों संग्रह ले सकते हैं, सूची 1 और सूची 2 कह सकते हैं।

फिर बस लिखो

list1.RemoveAll(Item => list2.Contains(Item));

यह काम करेगा।


3
अच्छा है लेकिन सूची से तत्वों को हटाने का दुष्प्रभाव है।
तारिक

7

उस स्थिति में जहां कोई ADO.NET एंटिटी फ्रेमवर्क का उपयोग कर रहा है , इकोस्टॉर्म का समाधान भी पूरी तरह से काम करता है। लेकिन इसके चारों ओर अपना सिर लपेटने में मुझे कुछ मिनट लगे। मान लें कि आपके पास एक डेटाबेस संदर्भ है, डीसी, और तालिका x में पंक्तियों को तालिका x में लिंक नहीं करना चाहते हैं, तो इसका पूरा उत्तर इस प्रकार दिखता है:

var linked =
  from x in dc.X
  from y in dc.Y
  where x.MyProperty == y.MyProperty
  select x;
var notLinked =
  dc.X.Except(linked);

एंडी की टिप्पणी के जवाब में, हां, एक LINQ क्वेरी में दो से हो सकता है। यहां सूचियों का उपयोग करते हुए एक पूर्ण कार्य उदाहरण दिया गया है। प्रत्येक वर्ग, फू और बार में एक आईडी है। फू के पास बार के माध्यम से Foo.BarId का "विदेशी कुंजी" संदर्भ है। कार्यक्रम सभी फू का चयन एक संबंधित बार से जुड़ा नहीं है।

class Program
{
    static void Main(string[] args)
    {
        // Creates some foos
        List<Foo> fooList = new List<Foo>();
        fooList.Add(new Foo { Id = 1, BarId = 11 });
        fooList.Add(new Foo { Id = 2, BarId = 12 });
        fooList.Add(new Foo { Id = 3, BarId = 13 });
        fooList.Add(new Foo { Id = 4, BarId = 14 });
        fooList.Add(new Foo { Id = 5, BarId = -1 });
        fooList.Add(new Foo { Id = 6, BarId = -1 });
        fooList.Add(new Foo { Id = 7, BarId = -1 });

        // Create some bars
        List<Bar> barList = new List<Bar>();
        barList.Add(new Bar { Id = 11 });
        barList.Add(new Bar { Id = 12 });
        barList.Add(new Bar { Id = 13 });
        barList.Add(new Bar { Id = 14 });
        barList.Add(new Bar { Id = 15 });
        barList.Add(new Bar { Id = 16 });
        barList.Add(new Bar { Id = 17 });

        var linked = from foo in fooList
                     from bar in barList
                     where foo.BarId == bar.Id
                     select foo;
        var notLinked = fooList.Except(linked);
        foreach (Foo item in notLinked)
        {
            Console.WriteLine(
                String.Format(
                "Foo.Id: {0} | Bar.Id: {1}",
                item.Id, item.BarId));
        }
        Console.WriteLine("Any key to continue...");
        Console.ReadKey();
    }
}

class Foo
{
    public int Id { get; set; }
    public int BarId { get; set; }
}

class Bar
{
    public int Id { get; set; }
}

LINQ में दो से बदतर? यह उपयोगी होगा।
एंडी

एंडी: हाँ, ऊपर संशोधित उत्तर देखें।
ब्रेट

4
var secondEmails = (from item in list2
                    select new { Email = item.Email }
                   ).ToList();

var matches = from item in list1
              where !secondEmails.Contains(item.Email)
              select new {Email = item.Email};


2

जबकि Exceptजवाब का हिस्सा है, यह पूरा जवाब नहीं है। डिफ़ॉल्ट रूप से, Except(LINQ ऑपरेटरों में से कई की तरह) संदर्भ प्रकारों पर एक संदर्भ तुलना करता है। वस्तुओं में मूल्यों की तुलना करने के लिए, आपको करना होगा

  • IEquatable<T>अपने प्रकार में लागू , या
  • ओवरराइड Equalsऔर GetHashCodeअपने प्रकार में, या
  • IEqualityComparer<T>अपने प्रकार के लिए लागू होने वाले एक प्रकार के उदाहरण में पास करें

2
... अगर हम LINQ के बारे में ऑब्जेक्ट्स के बारे में बात कर रहे हैं। यदि यह LINQ to SQL था, तो क्वेरी का अनुवाद SQL स्टेटमेंट में किया जाता है जो डेटाबेस पर चलता है, इसलिए यह लागू नहीं होता है।
लुकास

1

सादगी के लिए उदाहरण की सूची का उपयोग करके उदाहरण।

List<int> list1 = new List<int>();
// fill data
List<int> list2 = new List<int>();
// fill data

var results = from i in list1
              where !list2.Contains(i)
              select i;

foreach (var result in results)
    Console.WriteLine(result.ToString());

1

जो भी INC # में SQL-alike ऑपरेटर का उपयोग करना चाहते हैं , वे इस पैकेज को डाउनलोड करें:

Mshwf.NiceLinq

इसकी विधियाँ Inऔर NotInविधियाँ हैं:

var result = list1.In(x => x.Email, list2.Select(z => z.Email));

यहां तक ​​कि आप इसे इस तरह से उपयोग कर सकते हैं

var result = list1.In(x => x.Email, "a@b.com", "b@c.com", "c@d.com");

0

धन्यवाद, ब्रेट। आपके सुझाव से मुझे भी मदद मिली। मेरे पास वस्तुओं की एक सूची थी और वस्तुओं की एक अन्य सूची का उपयोग करके फ़िल्टर करना चाहते थे। एक बार फिर धन्यवाद....

अगर किसी को ज़रूरत है, तो कृपया मेरे कोड नमूने पर एक नज़र डालें:

'First, get all the items present in the local branch database
Dim _AllItems As List(Of LocalItem) = getAllItemsAtBranch(BranchId, RecordState.All)

'Then get the Item Mappings Present for the branch
Dim _adpt As New gItem_BranchesTableAdapter
Dim dt As New ds_CA_HO.gItem_BranchesDataTable
    _adpt.FillBranchMappings(dt, BranchId)

Dim _MappedItems As List(Of LocalItem) = (From _item As LocalItem In _AllItems Join _
    dr As ds_CA_HO.gItem_BranchesRow In dt _
    On _item.Id Equals dr.numItemID _
    Select _item).ToList

_AllItems = _AllItems.Except(_MappedItems.AsEnumerable).ToList

 Return _AllItems

0

मैंने LINQ से Entities के लिए इसका परीक्षण नहीं किया :

NorthwindDataContext dc = new NorthwindDataContext();    
dc.Log = Console.Out;

var query =    
    from c in dc.Customers 
    where !dc.Orders.Any(o => o.CustomerID == c.CustomerID)   
    select c;

वैकल्पिक रूप से:

NorthwindDataContext dc = new NorthwindDataContext();    
dc.Log = Console.Out;

var query =    
    from c in dc.Customers 
    where dc.Orders.All(o => o.CustomerID != c.CustomerID)   
    select c;

foreach (var c in query) 
    Console.WriteLine( c );

0

क्या आप बाहरी सूची में शामिल नहीं हो सकते हैं, केवल समूह खाली होने पर पहली सूची से आइटम का चयन कर सकते हैं? कुछ इस तरह:

Dim result = (From a In list1
              Group Join b In list2 
                  On a.Value Equals b.Value 
                  Into grp = Group
              Where Not grp.Any
              Select a)

मैं अनिश्चित हूं कि क्या यह इकाई ढांचे के साथ किसी भी प्रकार के कुशल तरीके से काम करेगा।


0

वैकल्पिक रूप से आप ऐसा कर सकते हैं:

var result = list1.Where(p => list2.All(x => x.Id != p.Id));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.