【问题标题】:Get the result of two compared list and change an attribut in list deponding on the result using LINQ使用 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}

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

【问题讨论】:

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

标签: c# wpf list linq


【解决方案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。如果你想要两个不同的对象,你应该克隆原来的那个。

【讨论】:

    猜你喜欢
    • 2020-07-06
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多