使用 LINQ 获取两个比较列表的结果并根据结果更改列表中的属性

Posted

技术标签:

【中文标题】使用 LINQ 获取两个比较列表的结果并根据结果更改列表中的属性【英文标题】:Get the result of two compared list and change an attribut in list deponding on the result using LINQ 【发布时间】:2021-11-28 08:24:22 【问题描述】:

我有两个对象列表,假设第一个称为部门,第二个称为学生。

public class Student 

   public int Id get; set; 

   public string Name get; set; 

   public bool IsActive get; set; 
  
   public int DepId get;set; 



 public class Department 

       public int DepId get; set; 

       public string DepName get; set; 
    

备注:用户列表中包含许多对象(超过 150 000 项)。

因此,我使用了Task.Run()

 private async Task UpdateMyGrid()
    
       departments = ....; // list of departments 
       students = ..... ;  // list of students
        await Task.Run(() =>
        
            var results = students.Where(x => departments.Any(y => y.DepId== x.DepId));

            foreach (var s in students)
            
                if (results.ToList().Exists(p => p.DepId== s.DepId))
                
                    s.IsEnabled = false;
                
            
            GridViewStudent.ItemsSource = null;
            GridViewStudent.ItemsSource = students;
        );
    

我想比较两个用户和部门列表并得到它们之间的结果,然后将属性 IsActive 设置为 false 。

例子:

List students: 1,"John",True,001 , 2,"Mariah",True,003,3,"Karima",True,002,4,"Jenny",True,004

List departments: 001,"Science" , 002,"Culture"

预期结果:

 Results will be => 1,"John",True,001,3,"Karima",True,002

 Students will be => 1,"John",False,001 , 2,"Mariah",True,003,
3,"Karima",False,002,4,"Jenny",True,004

我该怎么做才能使上述代码正常工作?

【问题讨论】:

但是不使用它我的用户界面被屏蔽了 实际问题是什么?你有预期的输入/输出吗? 我举个例子。 立即查看更新。 我不明白逻辑 - 预期和实际之间的逻辑是什么?您是否尝试根据部门是否存在来修改学生活动状态?你想输出结果还是学生? 【参考方案1】:

试试这个

private async Task UpdateMyGrid()

    
    await Task.Run(() =>
    
        
        foreach (var s in students)
        
            if (departments.Exists(p => p.DepId == s.DepId))
            
                s.IsActive= true;
            else s.IsActive=false;
        
        GridViewStudent.ItemsSource = null;
        GridViewStudent.ItemsSource = students;
    );

输出

    1   John    True    1
    2   Mariah  False   3
    3   Karima  True    2
    4   Jenny   False   4

或者如果你出于某种原因期望相反,你可以使用它,它也在使用 TPL 库

await Task.Run(() =>
    

        Parallel.ForEach(students, s =>
           
               if (departments.Exists(p => p.DepId == s.DepId))
            
                s.IsActive= false;
            else s.IsActive=true;
        );

输出

    1   John    False   1
    2   Mariah  True    3
    3   Karima  False   2
    4   Jenny   True    4

但恕我直言,最快的方法是如果您已经在数据库服务器中左连接学生和部门

var students =  await (from s in context.students
                join d in context.departments on s.DepId equals d.DepId into gj
                     from d in gj.DefaultIfEmpty()
                     select new Student
                 
                     Id=s.Id,
                     Name=s.Name,
                     DepId=s.DepId,
                     DepExist= d==null?false: true,
                 ).ToListAsync();

    Parallel.ForEach(students, s =>
           
               s.IsActive = s.DepExist;
            );

在这种情况下,您需要向学生添加一个属性

[NotMapped]
public bool DepExist  get; set; 

【讨论】:

OP 说预期的输出是1,"John",False,001 , 2,"Mariah",True,003, 3,"Karima",False,002,4,"Jenny",True,004 ? @ErmiyaEskandary 谢谢,我放了 2 个变体,因为它很混乱。我想如果一个部门存在,那么一个学生是活跃的 这里一样,不用担心 - 等待 OP 是的,学生名单取决于部门。我将搜索学生中的学生是否存在于部门列表中,isActive 将是False @csharp_devloper31 很难用两个词来解释。您可以阅读本教程,例如 dotnettutorials.net/lesson/parallel-foreach-method-csharp【参考方案2】:

我认为您想提高性能。 为此,您可以使用 Parallel.For 而不是 foreach 循环,因为您有很多对象。

            Parallel.ForEach(students, s =>
            
               if (results.ToList().Exists(p => p.DepId== s.DepId))
                
                    s.IsActive  = false;
                
            );

在 System.Threading.Tasks 中可用;

【讨论】:

谢谢,但问题与性能无关,请再次阅读我的问题。【参考方案3】:

将部门 ID 存储在 HashSet<int>:

var hashSet = new HashSet<int>(departments.Select(x => x.DepId));

...并遍历学生:

var results = new List<Student>();
foreach (var student in students)
 
    if (hashSet.Contains(student.DepId)
    
        results.Add(student);
        student.IsActive = false;
     

由于每个学生只有一个 Student 对象,因此 IsActive 属性不能在一个集合中为 true 而在另一个集合中为 false。如果你想要两个不同的对象,你应该克隆原来的那个。

【讨论】:

以上是关于使用 LINQ 获取两个比较列表的结果并根据结果更改列表中的属性的主要内容,如果未能解决你的问题,请参考以下文章

如何使用LINQ中的条件重新排列选择结果

使用LINQ从两个表(join)获取数据,并使用MVC 5将结果返回到View

比较两个列表并使用 linq 返回不匹配的项目

用 linq 查找和替换列表的结果

从 LINQ 查询的一部分中获取值并将其添加到结果中

使用Linq获取列表中对象的索引[重复]