简体   繁体   English

在Linq中比较两个IEnumerable(或列表)的最有效方法?

[英]Most efficient way to compare two IEnumerables (or lists) in Linq?

I've come across this a few times and I feel like I'm always writing unessasary code. 我已经遇到过几次,感觉就像我一直在写无文字的代码。 I'm looking for the most efficient way to compare the value of a field in a list with another list. 我正在寻找最有效的方法来比较列表中的字段值和另一个列表。

For example, let's say I have a viewmodel such as the following: 例如,假设我有一个如下的视图模型:

    public class UserContractAddDTO
    {
        public string ContractId { get; set; }
        public bool ContractSelected { get; set; }
        public string UserName { get; set; }
    }

I put the values of the table into this view model, and then pass it back as an IEnumerable: 我将表的值放入此视图模型中,然后将其作为IEnumerable传递回:

 IEnumerable<UserContractAddDTO> jsonArray

Now that I have this IEnumerable of UserContractAddDTO's, I will need to loop through it to compare the values that exist already in the database. 现在,有了UserContractAddDTO的IEnumerable,我将需要遍历它以比较数据库中已经存在的值。

Let's say ContractSelected has been updated for some of the rows, so it's set to true. 假设ContractSelected已针对某些行进行了更新,因此将其设置为true。 Normally I would use a foreach loop, but it would need to know if the row already exists to avoid duplicate rows. 通常我会使用一个foreach循环,但是它需要知道该行是否已经存在以避免重复的行。

        foreach (UserContractAddDTO u in jsonArray)
        {
            var a = u.ContractId.ToString();
            if (u.ContractSelected == true)
            {
                foreach (UserPlanSponsorContract up in UserContractList)
                {
                    if (up.PlanSponsorContractId.ToString() == a  && up.UserId == userId)
                    {
                        //update row
                        var row = _context.UserPlanSponsorContracts.Where(r => r.PlanSponsorContractId.ToString() == u.ContractId && r.UserId == userId).FirstOrDefault();
                        row.IsVerified = true;
                        _context.SaveChanges();
                    }
                    else
                    {
                        //add row
                        _context.UserPlanSponsorContracts.Add(new UserPlanSponsorContract
                        {
                            UserId = userId,
                            PlanSponsorContractId = Convert.ToInt32(u.ContractId),
                            IsVerified = true,
                            ContractAdminEmailSent = false,
                            AppliedDate = DateTime.Now,
                            ReverifyReminder = 0
                        });
                        _context.SaveChanges();
                    }
                }
            }
            else
            {
            foreach (UserPlanSponsorContract up in UserContractList)
            {
                if (up.PlanSponsorContractId.ToString() == a && up.UserId == userId)
                {
                    //update row
                    var row = _context.UserPlanSponsorContracts.Where(r => r.PlanSponsorContractId.ToString() == u.ContractId && r.UserId == userId).FirstOrDefault();
                    row.IsVerified = false;
                    _context.SaveChanges();
                }
                }
            }
        }

This is one approach I've tried, but I'm looking for a more efficient way of doing it. 这是我尝试过的一种方法,但是我正在寻找一种更有效的方法。 Thoughts? 思考?

As a general rule, the approach you need to take heavily depends on the structure of your program. 通常,您需要采取的方法很大程度上取决于程序的结构。 It basically comes down to reference type equality vs value equality. 基本上可以归结为引用类型相等与值相等。

If the objects in both lists are, in fact, the same object, then you do the following: 如果两个列表中的对象实际上是同一对象,则请执行以下操作:

var diff = myList.Except(myOtherList).ToList();

If, like in your case, you are dealing with value equality (two different objects, but the same "value"), then you first need to tell C# what makes two instances of your object equal. 如果像您的情况一样,您正在处理值相等(两个不同的对象,但是相同的“值”),那么您首先需要告诉C#是什么使对象的两个实例相等。 You need to define equality. 您需要定义平等。

For doing this there are two schools of thought. 为此,有两种思想流派。 You can modify your existing class and make it implement IEquatable , or you can create a brand new class which implements IEqualityComparer , whos job it will be to compare instances of your class. 您可以修改现有的类并使其实现IEquatable ,也可以创建一个实现IEqualityComparer全新类,该工作是比较类的实例。

You can see a detailed example of the former approach in this answer by Prashanth Thurairatnam , and an one of the latter approach in this answer by Jon Skeet . 你可以看到前一种方法的详细示例答案由普拉香特Thurairatnam ,而在后一种方法的一个答案由乔恩斯基特

In both cases, you will have to implement two methods, Equals(T, T) and GetHashCode(T) . 在这两种情况下,您都必须实现两种方法, Equals(T, T)GetHashCode(T) These methods will be used to figure out what makes two instances of your object equal. 这些方法将用于确定使对象的两个实例相等的原因。 Once you have done that the only code you need is that which I have written above (the only difference being that you also have to provide your comparer as an argument if you go with the IEqualityComparer approach). 完成操作后,所需的唯一代码就是我上面编写的代码(唯一的区别是,如果使用IEqualityComparer方法,则还必须提供比较器作为参数)。

LINQ isn't really designed for updating, so you would normally still need a foreach loop to process the results from the LINQ, but you don't need to repeat yourself so much. LINQ并不是真正为更新而设计的,因此通常您仍然需要一个foreach循环来处理LINQ的结果,但是您不需要重复太多。 Without knowing where UserContractList came from, I can't say if this could be further simplified. 不知道UserContractList来自何处,我不能说是否可以进一步简化。

foreach (UserContractAddDTO u in jsonArray) {
    var intContractId = Convert.ToInt32(u.ContractId);
    foreach (UserPlanSponsorContract up in UserContractList) {
        if (up.PlanSponsorContractId == intContractId && up.UserId == userId) {
            //update row
            var row = _context.UserPlanSponsorContracts.Where(r => r.PlanSponsorContractId == intContractId && r.UserId == userId).FirstOrDefault();
            row.IsVerified = u.ContractSelected;
        }
        else {
            //add row
            _context.UserPlanSponsorContracts.Add(new UserPlanSponsorContract {
                UserId = userId,
                PlanSponsorContractId = intContractId,
                IsVerified = true,
                ContractAdminEmailSent = false,
                AppliedDate = DateTime.Now,
                ReverifyReminder = 0
            });
        }
    }
    _context.SaveChanges();
}
using System;
using System.Collections.Generic;

namespace SwapArrayVal
{
    class A
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {

            List<A> list = new List<A>();
            list.Add(new A() { ID = 1, Name = "Pradeep" });
            list.Add(new A() { ID = 2, Name = "Binod" });


            IEnumerable<A> en1 = list;


            List<A> list2 = new List<A>();
            list2.Add(new A() { ID = 1, Name = "Pradeep" });
            list2.Add(new A() { ID = 2, Name = "Binod" });


            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            string outputOfInts = serializer.Serialize(list);
            string outputOfFoos = serializer.Serialize(list2);



            IEnumerable<A> en2 = list2;
            if (outputOfInts == outputOfFoos)
            {
                Console.Write("True");
            }

            Console.ReadLine();
        }
    }
}

Here you can compare two IEnumerable list 在这里您可以比较两个IEnumerable列表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM