Ответ 1
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
Я бы предположил, что для этого есть простой запрос 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
этом примере должны быть peopleList1
два человека (ID = 4 & ID = 5)
var result = peopleList2.Where(p => !peopleList1.Any(p2 => p2.ID == p.ID));
Если вы переопределите равенство людей, вы также можете использовать:
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));
Этот вариант не удаляет дубликаты.
Или если вы хотите его без отрицания:
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
В основном это говорит, что получить все от peopleList2, где все идентификаторы в peopleList1 отличаются от id в peopleList2.
Совсем другой подход от принятого ответа:)
Поскольку все решения на сегодняшний день используют свободный синтаксис, вот решение синтаксиса выражения запроса для заинтересованных:
var peopleDifference =
from person2 in peopleList2
where !(
from person1 in peopleList1
select person1.ID
).Contains(person2.ID)
select person2;
Я думаю, что он отличается от ответов, которые могут быть интересны некоторым, даже считал, что он скорее всего будет субоптимальным для списков. Теперь для таблиц с индексированными идентификаторами это определенно будет способом.
Бит опоздал на вечеринку, но хорошим решением, совместимым с 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
Клаус ответил великолепно, но ReSharper попросит вас "упростить выражение LINQ":
var result = peopleList2.Where(p => peopleList1.All(p2 => p2.ID != p.ID));
Это 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);
Вот рабочий пример, который позволяет ИТ-специалистам, чтобы кандидат на работу не уже есть.
//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);
во-первых, извлечь идентификаторы из коллекции, где условие
List<int> indexes_Yes = this.Contenido.Where(x => x.key == 'TEST').Select(x => x.Id).ToList();
во-вторых, используйте положение "сравнить", чтобы выбрать идентификаторы, различающиеся для выбора
List<int> indexes_No = this.Contenido.Where(x => !indexes_Yes.Contains(x.Id)).Select(x => x.Id).ToList();
Очевидно, вы можете использовать x.key! = "TEST", но это только пример
После того, как вы напишите общий 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);
}