J'ai deux collections qui ont la propriété Email
dans les deux collections. J'ai besoin d'obtenir une liste des éléments de la première liste où Email
n'existe pas dans la deuxième liste. Avec SQL, je voudrais simplement utiliser "not in", mais je ne connais pas l’équivalent dans LINQ. Comment est-ce fait?
Jusqu'à présent, j'ai une jointure, comme ...
var matches = from item1 in list1
join item2 in list2 on item1.Email equals item2.Email
select new { Email = list1.Email };
Mais je ne peux pas rejoindre car j'ai besoin de la différence et la jointure échouerait. J'ai besoin d'un moyen d'utiliser Contient or Exists, je crois. Je n'ai tout simplement pas trouvé d'exemple pour le faire.
Je ne sais pas si cela vous aidera mais ..
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 );
à partir de la clause NOT IN dans LINQ to SQL par Marco Russo
Vous voulez l'opérateur Sauf.
var answer = list1.Except(list2);
Meilleure explication ici: http://blogs.msdn.com/charlie/archive/2008/07/12/the-linq-set-operators.aspx
REMARQUE: Cette technique fonctionne mieux pour les types primitifs uniquement, car vous devez implémenter un IEqualityComparer pour utiliser la méthode Except avec des méthodes complexes. les types.
Pour les personnes qui commencent avec un groupe d'objets en mémoire et interrogent une base de données, j'ai trouvé que c'était la meilleure solution:
var itemIds = inMemoryList.Select(x => x.Id).ToArray();
var otherObjects = context.ItemList.Where(x => !itemIds.Contains(x.Id));
Ceci produit une clause Nice WHERE ... IN (...)
en SQL.
éléments de la première liste où l’email n’existe pas dans la deuxième liste.
from item1 in List1
where !(list2.Any(item2 => item2.Email == item1.Email))
select item1;
Vous pouvez utiliser une combinaison de Où et N'importe qui pour ne pas trouver dans:
var NotInRecord =list1.Where(p => !list2.Any(p2 => p2.Email == p.Email));
Vous pouvez prendre les deux collections dans deux listes différentes, par exemple list1 et list2.
Ensuite, écrivez
list1.RemoveAll(Item => list2.Contains(Item));
Cela fonctionnera.
Dans le cas où on utilise le ADO.NET Entity Framework , la solution d'EchoStorm fonctionne également parfaitement. Mais il m'a fallu quelques minutes pour envelopper ma tête. En supposant que vous ayez un contexte de base de données, dc, et que vous souhaitiez trouver des lignes dans la table x non liées dans la table y, la réponse complète ressemble à ceci:
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);
En réponse au commentaire de Andy, oui, on peut en avoir deux dans une requête LINQ. Voici un exemple de travail complet, en utilisant des listes. Chaque classe, Foo et Bar, a un identifiant. Foo a une référence "clé étrangère" à Bar via Foo.BarId. Le programme sélectionne tous les Foo non liés à une barre correspondante.
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; }
}
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};
On pourrait aussi utiliser All()
var notInList = list1.Where(p => list2.All(p2 => p2.Email != p.Email));
Alors que Except
fait partie de la réponse, ce n'est pas toute la réponse. Par défaut, Except
(comme plusieurs opérateurs LINQ) effectue une comparaison de référence sur les types de référence. Pour comparer par les valeurs dans les objets, vous devrez
IEquatable<T>
dans votre type, ouEquals
et GetHashCode
dans votre type, ouIEqualityComparer<T>
pour votre typeExemple utilisant List of int pour plus de simplicité.
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());
Pour tous ceux qui souhaitent également utiliser un opérateur IN
similaire à SQL en C #, téléchargez ce package:
Mshwf.NiceLinq
Il a In
et NotIn
méthodes:
var result = list1.In(x => x.Email, list2.Select(z => z.Email));
Même vous pouvez l'utiliser de cette façon
var result = list1.In(x => x.Email, "[email protected]", "[email protected]", "[email protected]");
Je n'ai pas testé cela avec LINQ to 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;
Alternativement:
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 );
Merci Brett. Votre suggestion m'a aidé aussi. J'avais une liste d'objets et je voulais filtrer celle-ci en utilisant une autre liste d'objets. Merci encore....
Si quelqu'un en a besoin, veuillez consulter mon exemple de code:
'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
Ne pourriez-vous pas faire une jointure externe en sélectionnant uniquement les éléments de la première liste si le groupe est vide? Quelque chose comme:
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)
Je ne sais pas si cela fonctionnerait de manière efficace avec le cadre Entity.