使用LINQ动态比较两个对象列表

3

点击查看输出:

我有一个雇员类

public class Employee
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Age { get; set; }
        public string Address { get; set; }
        public string ContactNo { get; set; }
    }

并且具有填充方法以填充列表

private static void FillEmployeeList(ref List<Employee> lt1, ref List<Employee> lt2)
        {
            lt1 = new List<Employee> {new Employee{ID=1,Name="Kavya",Age="24",Address="No.1,Nehru Street,Chennai",ContactNo="9874521456"},
            new Employee{ID=2,Name="Ravi",Age="24",Address="Flat No.25/A1,Gandhi Street,Chennai",ContactNo="9658745258"},
            new Employee{ID=3,Name="Lavnya",Age="30",Address="No.12,Shastri nagar,Chennai",ContactNo="5214587896"},
            new Employee{ID=4,Name="Rupa",Age="31",Address="No.23/5,Nehru Street,Chennai",ContactNo="9874521256"},
            new Employee{ID=5,Name="Divya",Age="32",Address="No.1/227,Nehru Street,Chennai",ContactNo="8541256387"},            
            };

            lt2 = new List<Employee> {new Employee{ID=1,Name="Kavya",Age="24",Address="No.1,Nehru Street,Chennai",ContactNo="9874521456"},
            new Employee{ID=2,Name="Ravindran",Age="30",Address="Flat No.25/A1,Gandhi Street,Chennai",ContactNo="9658745258"},
            new Employee{ID=3,Name="Chandru",Age="30",Address="No.12,Shastri nagar,Chennai",ContactNo="5214587896"},
            new Employee{ID=4,Name="Rakesh",Age="32",Address="No.23/5,Nehru Street,Chennai",ContactNo="9874021256"},
            new Employee{ID=5,Name="Suresh",Age="32",Address="No.1/227,Nehru Street,Chennai",ContactNo="8541056387"},
            new Employee{ID=11,Name="Suryakala",Age="28",Address="No.1,Pillayar koil Street,Chennai",ContactNo="9541204782"},
            new Employee{ID=12,Name="Thivya",Age="41",Address="No.42,Ellaiamman koil Street,Chennai",ContactNo="9632140874"},           
            };
        }

比较两个对象列表

protected List<Employee> ListCompare(List<Employee> lt1, List<Employee> lt2)
        {
            FillEmployeeList(ref lt1, ref lt2);
            List<Employee> lst = new List<Employee>();

            if (lt1.Count > 0 && lt2.Count > 0)
            {
                // Displaying Matching Records from List1 and List2 by ID

                var result = (from l1 in lt1
                              join l2 in lt2
                              on l1.ID equals l2.ID
                              orderby l1.ID
                              select new
                              {

                                  ID = l1.ID,
                                  Name = (l1.Name == l2.Name) ? "$" : (l2.Name + " (Modified)"),
                                  Age = (l1.Age == l2.Age) ? "$" : (l2.Age + " (Modified)"),
                                  Address = (l1.Address == l2.Address) ? "$" : (l2.Address + " (Modified)"),
                                  ContactNo = (l1.ContactNo == l2.ContactNo) ? "$" : (l2.ContactNo + " (Modified)")
                              }).ToList();

                // Displaying Records from List1 which is not in List2
                var result1 = from l1 in lt1
                              where !(from l2 in lt2
                                      select l2.ID).Contains(l1.ID)
                              orderby l1.ID
                              select new
                              {
                                  ID = l1.ID,
                                  Name = " Deleted",
                                  Age = " Deleted",
                                  Address = " Deleted",
                                  ContactNo = " Deleted"
                              };

                // Displaying Records from List1 which is not in List2
                var result2 = from l1 in lt2
                              where !(from l2 in lt1
                                      select l2.ID).Contains(l1.ID)
                              orderby l1.ID
                              select new
                              {
                                  ID = l1.ID,
                                  Name = l1.Name + " (Added)",
                                  Age = l1.Age + " (Added)",
                                  Address = l1.Address + " (Added)",
                                  ContactNo = l1.ContactNo + " (Added)"
                              };

                var res1 = result.Concat(result1).Concat(result2);

                foreach (var item in res1)
                {
                    Employee emp = new Employee();
                    //Response.Write(item + "<br/>");
                    emp.ID = item.ID;
                    emp.Name = item.Name;
                    emp.Age = item.Age;
                    emp.Address = item.Address;
                    emp.ContactNo = item.ContactNo;
                    lst.Add(emp);
                }
            }
            return lst;
        }

这里我正在调用compareList方法,并返回结果并在HTML表格中显示。

List<Employee> lt1 = new List<Employee>();
                List<Employee> lt2 = new List<Employee>();
                List<Employee> resultset = new List<Employee>();
                //string value = "ID";
                StringBuilder htmlTable = new StringBuilder();
                htmlTable.Append("<table border='1'>");
                htmlTable.Append("<tr><th>ID</th><th>Name</th><th>Age</th><th>Address</th><th>ContactNo</th></tr>");
                resultset = ListCompare(lt1, lt2);
                foreach(var item in resultset)
                {
                    htmlTable.Append("<tr>");
                    htmlTable.Append("<td>" + item.ID + "</td>");
                    htmlTable.Append("<td>" + item.Name + "</td>");
                    htmlTable.Append("<td>" + item.Age + "</td>");
                    htmlTable.Append("<td>" + item.Address + "</td>");
                    htmlTable.Append("<td>" + item.ContactNo + "</td>");
                    htmlTable.Append("</tr>");
                }
                htmlTable.Append("</table>");
                PlaceHolder1.Controls.Add(new Literal { Text = htmlTable.ToString() });

我的问题是如何将这段代码泛化。我可能有任何类(例如Employee或Student)。我希望编写的代码只需将两个对象列表传递给CompareMethod(我将传递任何类型的对象列表以进行比较),它将返回列表作为结果。如何操作,请提供任何想法。

实现一个公共接口。 - Tommy
你能用代码详细解释一下吗? - Poongodi
2个回答

0
如果您对集合的相等性感兴趣,我想推荐下面的内容: 通过使用指定的IEqualityComparer比较它们的元素,确定两个序列是否相等。MSDN
在单元测试的情况下: CollectionAssert.AreEquivalent
验证两个指定的集合是否相等。如果集合不相等,则断言失败。MSDN
如果您需要了解差异: Enumerable.Except
生成两个序列的集合差异。MSDN

0
您可以按照以下方式创建比较方法:
protected List<TResult> ListCompare<TKey, TInput, TResult>(List<TInput> lt1, List<TInput> lt2, Func<TInput, TKey> key,  Func<TInput, TInput, TResult> modified, Func<TInput, TResult> added, Func<TInput, TResult> deleted)
{
    // Displaying Matching Records from List1 and List2 by ID
    var matchingEmployees = lt1.Join(lt2, key, key, modified);

    // Displaying Records from List1 which is not in List2
    var lt1NotInlt2 = lt1
          .Where(e1 => !lt2.Any(e2 => key(e2).Equals(key(e1))))
          .Select(deleted);

    // Displaying Records from List2 which is not in List1
    var lt2NotInlt1 = lt2
          .Where(e2 => !lt1.Any(e1 => key(e1).Equals(key(e2))))
          .Select(added);

    return matchingEmployees.Concat(lt1NotInlt2).Concat(lt2NotInlt1).ToList();
}

如果您不想使用键,那么您的比较方法应该像这样,并且您的类应该实现Equals方法:

protected List<TResult> ListCompare<TInput, TResult>(List<TInput> lt1, List<TInput> lt2, Func<TInput, TInput, TResult> modified, Func<TInput, TResult> added, Func<TInput, TResult> deleted)
{
    // Displaying Matching Records from List1 and List2 by ID
    var matchingEmployees = lt1
        .Where(e1 => lt2.Any(e2 => e2.Equals(e1)))
        .Select(e1 =>
        {
            var e2 = lt2.First(e => e.Equals(e1));

            return modified(e1, e2);
        });

    // Displaying Records from List1 which is not in List2
    var lt1NotInlt2 = lt1
        .Where(e1 => !lt2.Any(e2 => e2.Equals(e1)))
        .Select(deleted);

    // Displaying Records from List2 which is not in List1
    var lt2NotInlt1 = lt2
        .Where(e2 => !lt1.Any(e1 => e1.Equals(e2)))
        .Select(added);

    return matchingEmployees.Concat(lt1NotInlt2).Concat(lt2NotInlt1).ToList();
}

然后你可以像这样调用compare方法:

var result = ListCompare<int, Employee, Employee>(
    lt1,
    lt2,
    e => e.ID,
    (e1, e2) => new Employee
    {
        ID = e1.ID,
        Name = (e1.Name == e2.Name) ? "$" : (e2.Name + " (Modified)"),
        Age = (e1.Age == e2.Age) ? "$" : (e2.Age + " (Modified)"),
        Address = (e1.Address == e2.Address) ? "$" : (e2.Address + " (Modified)"),
        ContactNo = (e1.ContactNo == e2.ContactNo) ? "$" : (e2.ContactNo + " (Modified)")
     },
     e => new Employee
     {
          ID = e.ID,
          Name = e.Name + " (Added)",
          Age = e.Age + " (Added)",
          Address = e.Address + " (Added)",
          ContactNo = e.ContactNo + " (Added)"
      },
      e => new Employee
      {
          ID = e.ID,
          Name = " Deleted",
          Age = " Deleted",
          Address = " Deleted",
          ContactNo = " Deleted"
      });

我已经得到了输出,但我想以“添加”、“修改”等形式显示文本。例如,如果特定ID的地址相同,则显示$符号与结果一起。如何做到这一点? - Poongodi
还有在LINQ中按字段进行比较,这是可能的吗? - Poongodi
调用ListCompare方法时出现语法错误。 - Poongodi
应该已经修复了! - Timothy Ghanem
你好,是否可以在上述代码中比较两个列表而不使用任何键? - Poongodi
我只想在ListCompare方法中比较没有任何公共字段的内容。我在没有公共字段的Join表达式中遇到了错误。如何解决这个问题? - Poongodi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接