从列表中排除另一个列表中的项目

时间:2015-12-03 19:54:08

标签: c# linq

我有一个例如List<string> ListProviderKeys的列表,其中包含一些值。 我还有下面一个类的第二个列表,例如List<ChangesSummary> SecondList;

public class ChangesSummary
{
    public string TableName { get; set; }
    public string ProviderKey { get; set; }
    public string ProviderAdrsKey { get; set; }
    public string ProviderSpecialtyKey { get; set; }
    public string FieldName{ get; set; }
}

想象一下,第一个列表保存的值与我们在第二个列表中放入ProviderKey字段的值相同。 现在我想要的是缩小第二个列表,使其ProviderKey 的值已经存在于第一个列表中。 我怎样才能做到这一点?我知道操作员除了但不确定如何在这种情况下应用它!

4 个答案:

答案 0 :(得分:1)

我能想到的最好的是:

A)创建字典并使用其快速查找

B)在此字典中使用LINQ .Where方法和.ContainsKey(),该字典在内部使用Hashtable并执行快速查找。

这会将搜索复杂性降低到差不多O(1)而不是O(N)更糟(当我们使用LINQ .Where().Any().Contains()时,这会导致嵌套循环)。

来自MSDN page

  

Dictionary泛型类提供从一组键到的映射   一组价值观。字典的每个添加都包含一个值   及其相关密钥。使用其键检索值非常有用   快,接近O(1),因为Dictionary类实现为   哈希表。

所以我们能做的是:

Dictionary<string, string> dict = ListProviderKeys.ToDictionary(s => s);

var newList = SecondList.Where(e => !dict.ContainsKey(e.ProviderKey)).ToList();

这是一个非常简单,简短但完整的示例,说明了它并测试了它的性能:

class Person
{
    public int Id { get; set; }        
}

class Program
{
    static void Main(string[] args)
    {
        List<int> ints = new List<int>();
        List<Person> People = new List<Person>(1000);

        for (int i = 0; i < 7500; i++)
        {
            ints.Add(i);
            ints.Add(15000 - i - 1);
        }

        for (int i = 0; i < 45000; i++)
            People.Add(new Person() { Id = i });

        Stopwatch s = new Stopwatch();

        s.Start();

        // code A (feel free to uncomment it)         
        //Dictionary<int, int> dict = ints.ToDictionary(p => p);

        //List<Person> newList = People.Where(p => !dict.ContainsKey(p.Id)).ToList();

        // code B
        List<Person> newList = People.Where(p => !ints.Contains(p.Id)).ToList();

        s.Stop();

        Console.WriteLine(s.ElapsedMilliseconds);
        Console.WriteLine("Number of elements " + newList.Count);

        Console.ReadKey();
    }

发布模式下,结果为:

代码A&amp;代码B输出30 000个元素但是:

代码B花了超过2000毫秒,代码A花了5毫秒

答案 1 :(得分:0)

 public class Programm
    {
        public static void Main()
        {
             List<ChangesSummary>  summaries = new List<ChangesSummary>();

             summaries.Add(new ChangesSummary()
             {
                 FieldName = "1",
                 ProviderKey = "Test1",
             });

             summaries.Add(new ChangesSummary()
             {
                 FieldName = "2",
                 ProviderKey = "Test2",
             });

             summaries.Add(new ChangesSummary()
             {
                 FieldName = "3",
                 ProviderKey = "Test3",
             });

            List<string> listProviderKeys = new List<string>();

            listProviderKeys.Add("Test1");
            listProviderKeys.Add("Test3");

            var res = summaries.Where(x => !listProviderKeys.Contains(x.ProviderKey));


            res.ToList().ForEach(x => Console.WriteLine(x.ProviderKey));

            Console.ReadLine();
        }
    }

    public class ChangesSummary
    {
        public string TableName { get; set; }
        public string ProviderKey { get; set; }
        public string ProviderAdrsKey { get; set; }
        public string ProviderSpecialtyKey { get; set; }
        public string FieldName { get; set; }
    }

答案 2 :(得分:-1)

我认为在这种情况下,简单Where将更容易,更易于应用。

var first = new List<string> { "a" };
var second = new List<ChangesSummary>()
{
    new ChangesSummary() { ProviderKey = "a" },
    new ChangesSummary() { ProviderKey = "b" }
};

var result = second.Where(item => !first.Contains(item.ProviderKey));

// result
//    .ToList()
//    .ForEach(item => Console.WriteLine(item.ProviderKey));

答案 3 :(得分:-2)

我相信这会奏效:

List<ChangesSummary> ExceptionList = SecondList.
Where(x => !ListProviderKeys.Any(key => x.ProviderKey == key)).ToList();