我会假设有一个简单的 LINQ 查询可以做到这一点,我只是不完全确定如何。
鉴于这段代码:
class Program
{
static void Main(string[] args)
{
List<Person> peopleList1 = new List<Person>();
peopleList1.Add(new Person() { ID = 1 });
peopleList1.Add(new Person() { ID = 2 });
peopleList1.Add(new Person() { ID = 3 });
List<Person> peopleList2 = new List<Person>();
peopleList2.Add(new Person() { ID = 1 });
peopleList2.Add(new Person() { ID = 2 });
peopleList2.Add(new Person() { ID = 3 });
peopleList2.Add(new Person() { ID = 4 });
peopleList2.Add(new Person() { ID = 5 });
}
}
class Person
{
public int ID { get; set; }
}
我想执行一个 LINQ 查询,以提供 peopleList2
中所有不在 peopleList1
中的人。
这个例子应该给我两个人(ID = 4 & ID = 5)
这可以使用以下 LINQ 表达式来解决:
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
通过 LINQ 表达这一点的另一种方式,一些开发人员发现它更具可读性:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
警告:如评论中所述,这些方法要求 O(n*m) 操作。这可能很好,但可能会引入性能问题,尤其是在数据集非常大的情况下。如果这不能满足您的性能要求,您可能需要评估其他选项。但是,由于所述要求是针对 LINQ 中的解决方案,因此此处不探讨这些选项。与往常一样,根据您的项目可能具有的性能要求评估任何方法。
如果您覆盖 People 的平等性,那么您还可以使用:
peopleList2.Except(peopleList1)
Except
应该比 Where(...Any)
变体快得多,因为它可以将第二个列表放入哈希表中。 Where(...Any)
的运行时间为 O(peopleList1.Count * peopleList2.Count)
,而基于 HashSet<T>
的变体(几乎)的运行时间为 O(peopleList1.Count + peopleList2.Count)
。
Except
隐式删除重复项。这不应该影响您的情况,但可能是类似情况的问题。
或者,如果您想要快速代码但不想覆盖相等性:
var excludedIDs = new HashSet<int>(peopleList1.Select(p => p.ID));
var result = peopleList2.Where(p => !excludedIDs.Contains(p.ID));
此变体不会删除重复项。
Equals
被覆盖以比较 ID 时才有效。
或者如果你想要它没有否定:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
基本上它说从 peopleList2 中获取所有内容,其中 peopleList1 中的所有 id 都与 peoplesList2 中的 id 不同。
与接受的答案有点不同的方法:)
由于迄今为止所有的解决方案都使用流利的语法,这里有一个查询表达式语法的解决方案,对于那些感兴趣的人:
var peopleDifference =
from person2 in peopleList2
where !(
from person1 in peopleList1
select person1.ID
).Contains(person2.ID)
select person2;
我认为它与某些人感兴趣的答案有很大不同,甚至认为它很可能对列表来说不是最理想的。现在对于具有索引 ID 的表,这肯定是要走的路。
有点晚了,但一个很好的解决方案也是 Linq to SQL 兼容的:
List<string> list1 = new List<string>() { "1", "2", "3" };
List<string> list2 = new List<string>() { "2", "4" };
List<string> inList1ButNotList2 = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inList2ButNotList1 = (from o in list2
join p in list1 on o equals p into t
from od in t.DefaultIfEmpty()
where od == null
select o).ToList<string>();
List<string> inBoth = (from o in list1
join p in list2 on o equals p into t
from od in t.DefaultIfEmpty()
where od != null
select od).ToList<string>();
向http://www.dotnet-tricks.com/Tutorial/linq/UXPF181012-SQL-Joins-with-C致敬
此 Enumerable Extension 允许您定义要排除的项目列表和用于查找用于执行比较的键的函数。
public static class EnumerableExtensions
{
public static IEnumerable<TSource> Exclude<TSource, TKey>(this IEnumerable<TSource> source,
IEnumerable<TSource> exclude, Func<TSource, TKey> keySelector)
{
var excludedSet = new HashSet<TKey>(exclude.Select(keySelector));
return source.Where(item => !excludedSet.Contains(keySelector(item)));
}
}
你可以这样使用
list1.Exclude(list2, i => i.ID);
var result = peopleList2.Exclude(peopleList1, i => i.ID);
Klaus 的回答很好,但 ReSharper 会要求您“简化 LINQ 表达式”:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
一旦你编写了一个通用的 FuncEqualityComparer,你就可以在任何地方使用它。
peopleList2.Except(peopleList1, new FuncEqualityComparer<Person>((p, q) => p.ID == q.ID));
public class FuncEqualityComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> comparer;
private readonly Func<T, int> hash;
public FuncEqualityComparer(Func<T, T, bool> comparer)
{
this.comparer = comparer;
if (typeof(T).GetMethod(nameof(object.GetHashCode)).DeclaringType == typeof(object))
hash = (_) => 0;
else
hash = t => t.GetHashCode();
}
public bool Equals(T x, T y) => comparer(x, y);
public int GetHashCode(T obj) => hash(obj);
}
这是一个工作示例,可以获取求职者尚未具备的 IT 技能。
//Get a list of skills from the Skill table
IEnumerable<Skill> skillenum = skillrepository.Skill;
//Get a list of skills the candidate has
IEnumerable<CandSkill> candskillenum = candskillrepository.CandSkill
.Where(p => p.Candidate_ID == Candidate_ID);
//Using the enum lists with LINQ filter out the skills not in the candidate skill list
IEnumerable<Skill> skillenumresult = skillenum.Where(p => !candskillenum.Any(p2 => p2.Skill_ID == p.Skill_ID));
//Assign the selectable list to a viewBag
ViewBag.SelSkills = new SelectList(skillenumresult, "Skill_ID", "Skill_Name", 1);
首先,从条件集合中提取 id
List<int> indexes_Yes = this.Contenido.Where(x => x.key == 'TEST').Select(x => x.Id).ToList();
其次,使用“比较” estament 来选择与选择不同的 id
List<int> indexes_No = this.Contenido.Where(x => !indexes_Yes.Contains(x.Id)).Select(x => x.Id).ToList();
显然你可以使用 x.key != "TEST",但这只是一个例子
{
static void Main(string[] args)
{
List<Person> peopleList1 = new List<Person>();
peopleList1.Add(new Person() { ID = 1 });
peopleList1.Add(new Person() { ID = 2 });
peopleList1.Add(new Person() { ID = 3 });
List<Person> peopleList2 = new List<Person>();
peopleList2.Add(new Person() { ID = 1 });
peopleList2.Add(new Person() { ID = 2 });
peopleList2.Add(new Person() { ID = 3 });
peopleList2.Add(new Person() { ID = 4 });
peopleList2.Add(new Person() { ID = 5 });
}
var leftPeeps = peopleList2.Where(x => !peopleList1.Select(y => y.ID).Contains(x.ID))?.ToList() ?? new List<Person>();
}
class Person
{
public int ID { get; set; }
}
注意 !peopleList1.Select(y => y.ID).Contains(x.ID) Select 语句。这允许我们获取我们想要的索引器(ID)并查看它是否包含前一个列表的 ID。 !意味着我们不想要那些。这可能会让我们没有条目。因此,我们可以通过检查 null 并使用 null 合并来确保我们有一些东西。