Фильтрация списков с использованием LINQ

У меня есть список людей, которые возвращаются из внешнего приложения, и я создаю список исключений в моем локальном приложении, чтобы дать мне возможность вручную удалять людей из списка.

У меня есть составной ключ, который я создал, который является общим для обоих, и я хочу найти эффективный способ удаления людей из моего списка с помощью моего списка

например

class Person
{
    prop string compositeKey { get; set; }
}

class Exclusions
{
    prop string compositeKey { get; set; }
}

List<Person> people = GetFromDB;

List<Exclusions> exclusions = GetFromOtherDB;

List<Person> filteredResults = People - exclustions using the composite key as a comparer

Я думал, что LINQ был идеальным способом сделать это, но после попытки объединений, методов расширения, использования выходов и т. д. У меня все еще возникают проблемы.

Если бы это был SQL, я бы использовал запрос not in (?,?,?).

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
0
116 840
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Я не мог понять, как это сделать в чистом MS LINQ, поэтому написал для этого свой собственный метод расширения:

public static bool In<T>(this T objToCheck, params T[] values)
{
    if (values == null || values.Length == 0) 
    {
        return false; //early out
    }
    else
    {
        foreach (T t in values)
        {
            if (t.Equals(objToCheck))
                return true;   //RETURN found!
        }

        return false; //nothing found
    }
}

вы написали способ сделать "item.In (list)". уже есть метод, который выполняет «list.Contains (item)». так что вы можете реализовать In () как {return values.Contains (objToCheck); }

Lucas 13.02.2009 19:35

Я думаю, что мой код выглядит чище, и с помощью arrary параметров я могу создать свой список из параметров, встроенных в тот же запрос LINQ, вместо того, чтобы создавать новый список в коде повсюду. У меня это хорошо сработало.

Jason Jackson 13.02.2009 22:30

Я бы просто использовал метод FindAll в классе List. то есть:

List<Person> filteredResults = 
    people.FindAll(p => return !exclusions.Contains(p));

Не уверен, что синтаксис точно соответствует вашим объектам, но я думаю, вы видите, к чему я клоню.

FindAll был для меня правильным подходом. У меня был общий список, который мне нужно было передать через предикат bool, чтобы определить, должен ли возвращаемый список содержать этот элемент. Что-то вроде следующего - это то, что я искал. var permitted = overall.FindAll(x => IsPermitted(x));

Jay Gould 18.09.2019 14:25

Вы можете использовать метод расширения "Except" (см. http://msdn.microsoft.com/en-us/library/bb337804.aspx)

В вашем коде

var difference = people.Except(exclusions);

О, и вы можете предоставить свой собственный компаратор. Помните, что Except оптимизирован, потому что внутри он использует структуру Set.

Fabrizio C. 06.01.2009 19:46
Ответ принят как подходящий

Взгляните на метод Кроме, который вы используете следующим образом:

var resultingList = 
    listOfOriginalItems.Except(listOfItemsToLeaveOut, equalityComparer)

Вы захотите использовать перегрузку, с которой я связался, которая позволяет указать настраиваемый IEqualityComparer. Таким образом вы можете указать, как элементы совпадают на основе вашего составного ключа. (Однако, если вы уже переопределили Equals, IEqualityComparer вам не понадобится.)

Редактировать: Поскольку кажется, что вы используете два разных типа классов, вот еще один способ, который может быть проще. Предположим, что List<Person> называется persons, а List<Exclusion> называется exclusions:

var exclusionKeys = 
        exclusions.Select(x => x.compositeKey);
var resultingPersons = 
        persons.Where(x => !exclusionKeys.Contains(x.compositeKey));

Другими словами: выберите из исключений только ключи, затем выберите из лиц все объекты Person, у которых не есть какие-либо из этих ключей.

в его примере это две разные таблицы. Итак, личность и исключения - это разные типы, можно ли тогда использовать «Исключение»? потому что вы хотите передать IEnumerable <Exclusions> в person.Except <Person> (IEnumerable <Person>, IEqualityComparer <Person>);

Hath 06.01.2009 20:17

Хорошее замечание, Хат. Я добавил еще один метод, который не требует одного и того же типа для каждого списка.

Ryan Lundy 06.01.2009 22:27

Я бы сделал что-то подобное, но держу пари, что есть способ попроще. Я думаю, что sql из linqtosql будет использовать выбор от человека, где НЕ СУЩЕСТВУЕТ (выберите из списка исключений)

static class Program
{
    public class Person
    {
        public string Key { get; set; }
        public Person(string key)
        {
           Key = key;
        }
    }
    public class NotPerson
    {
        public string Key { get; set; }
        public NotPerson(string key)
        {
           Key = key;
        }
    }
    static void Main()
    {

       List<Person> persons = new List<Person>()
       { 
           new Person ("1"),
           new Person ("2"),
           new Person ("3"),
           new Person ("4")
       };

       List<NotPerson> notpersons = new List<NotPerson>()
       { 
           new NotPerson ("3"),
           new NotPerson ("4")
       };

       var filteredResults = from n in persons
                             where !notpersons.Any(y => n.Key == y.Key)
                             select n;

       foreach (var item in filteredResults)
       {
          Console.WriteLine(item.Key);
       }
    }
 }

Этот LINQ ниже сгенерирует SQL для левого внешнего соединения, а затем возьмет все результаты, которые не находят совпадения в вашем списке исключений.

List<Person> filteredResults =from p in people
        join e in exclusions on p.compositeKey equals e.compositeKey into temp
        from t in temp.DefaultIfEmpty()
        where t.compositeKey == null
        select p

дайте мне знать, если это сработает!

Большое спасибо за это, ребята.

Мне удалось свести это к одной строке:

  var results = from p in People 
                where !(from e in exclusions 
                        select e.CompositeKey).Contains(p.CompositeKey) 
                select p;

Еще раз спасибо всем.

            var result = Data.Where(x =>
            {
            bool condition = true;
            double accord = (double)x[Table.Columns.IndexOf(FiltercomboBox.Text)];
            return condition && accord >= double.Parse(FilterLowertextBox.Text) && accord <= double.Parse(FilterUppertextBox.Text); 
        });
var thisList = new List<string>{ "a", "b", "c" };
var otherList = new List<string> {"a", "b"};

var theOnesThatDontMatch = thisList
        .Where(item=> otherList.All(otherItem=> item != otherItem))
        .ToList();

var theOnesThatDoMatch = thisList
        .Where(item=> otherList.Any(otherItem=> item == otherItem))
        .ToList();

Console.WriteLine("don't match: {0}", string.Join(",", theOnesThatDontMatch));
Console.WriteLine("do match: {0}", string.Join(",", theOnesThatDoMatch));

//Output:
//don't match: c
//do match: a,b

Соответственно измените типы списков и лямбды, и вы сможете отфильтровать все, что угодно.

https://dotnetfiddle.net/6bMCvN

Другие вопросы по теме