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

时间:2017-07-25 20:26:58

标签: c# linq

我偶然遇到过这种情况,我觉得我总是在编写无用的代码。我正在寻找一种最有效的方法来比较列表中字段的值与另一个列表。

例如,假设我有一个视图模型,如下所示:

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

我将表的值放入此视图模型中,然后将其作为IEnumerable传递回来:

 IEnumerable<UserContractAddDTO> jsonArray

现在我有了这个IEnumerable的UserContractAddDTO,我需要遍历它来比较数据库中已存在的值。

我们假设ContractSelected已针对某些行进行了更新,因此将其设置为true。通常我会使用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();
                }
                }
            }
        }

这是我尝试过的一种方法,但我正在寻找一种更有效的方法。想法?

3 个答案:

答案 0 :(得分:2)

作为一般规则,您需要采取的方法很大程度上取决于程序的结构。它基本上归结为引用类型相等与值相等。

如果两个列表中的对象实际上是同一个对象,则执行以下操作:

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

如果在你的情况下,你正在处理价值相等(两个不同的对象,但相同的&#34;值&#34;),那么你首先需要告诉C#是什么让你的对象的两个实例相等。你需要定义相等。

为此,有两种思想流派。您可以修改现有的类并使其实现IEquatable,或者您可以创建一个实现IEqualityComparer的全新类,它将用于比较您的类的实例。

您可以在thisPrashanth Thurairatnam回答中看到前一种方法的详细示例,thisJon Skeet回答中的后一种方法之一。

在这两种情况下,您都必须实施两种方法Equals(T, T)GetHashCode(T)。这些方法将用于确定使对象的两个实例相等的原因。一旦你完成了,你需要的唯一代码就是我上面写的那些代码(唯一的区别是,如果你采用IEqualityComparer方法,你还必须提供你的比较器作为参数。)

答案 1 :(得分:0)

LINQ并非真正用于更新,因此您通常仍需要foreach循环来处理来自LINQ的结果,但您不需要重复这么多。在不知道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();
}

答案 2 :(得分:0)

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();
        }
    }
}

您可以在此处比较两个IEnumerable列表