26

我有一个从外部应用程序返回的人员列表,我正在本地应用程序中创建一个排除列表,以便我可以选择手动从列表中删除人员。

我有一个我创建的复合键,它对两者都是通用的,我想找到一种使用我的列表从我的列表中删除人员的有效方法

例如

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 (?,?,?)查询。

4

9 回答 9

43

看一下except方法,您可以像这样使用它:

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 对象。

于 2009-01-06T16:46:08.427 回答
9

我只会在 List 类上使用 FindAll 方法。IE:

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

不确定语法是否与您的对象完全匹配,但我认为您可以看到我的目标。

于 2009-01-06T16:43:40.197 回答
5

非常感谢这些家伙。

我设法将其归结为一行:

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

再次感谢大家。

于 2009-01-08T12:15:43.247 回答
4
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

相应地调整列表类型和 lambda,您可以过滤掉任何内容。

https://dotnetfiddle.net/6bMCvN

于 2018-05-02T18:43:26.537 回答
2

您可以使用“Except”扩展方法(参见http://msdn.microsoft.com/en-us/library/bb337804.aspx

在您的代码中

var difference = people.Except(exclusions);
于 2009-01-06T16:44:09.960 回答
1

我不知道如何在纯 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
    }
}
于 2009-01-06T16:41:45.240 回答
0

我会做这样的事情,但我敢打赌有一个更简单的方法。我认为来自 linqtosql 的 sql 将使用来自不存在的人的选择(从排除列表中选择)

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);
       }
    }
 }
于 2009-01-06T16:57:25.347 回答
0

下面的这个 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

让我知道它是否有效!

于 2009-01-06T17:09:09.847 回答
-1
            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); 
        });
于 2017-12-17T07:58:17.310 回答