比较两个列表与foreach循环,并从未找到的项目创建新的列表

本文关键字:列表 项目 创建 循环 两个 比较 foreach | 更新日期: 2023-09-27 18:01:36

很抱歉发了这么一个看似简单的问题。我知道有很多类似的问题已经发布了(在发布我的问题之前我已经看过其中的许多问题),但我很难将答案应用到我的情况中。我对c#比较陌生,非常感谢您的输入和帮助。

我如何比较我的2个Listsforeach循环,并创建一个新的List,其中发现的记录在我的比较中不存在?

下面是我已经拥有的代码大纲,以及需要发生的注释:

private void updateHolidays()
{
    List<Holiday> localHolidays = getLocalHolidays();
    List<Holiday> remoteHolidays = getRemoteHolidays();
    List<Holiday> holidayDifference = new List<Holiday>();
    foreach (Holiday holiday in remoteHolidays)
    {
        if (true) // holiday does not exist in localHolidays
        {
            // add holiday to holidayDifference
            holidayDifference.Add(holiday);
        }
    }
    createNewHolidays(holidayDifference);
}

提前感谢!

比较两个列表与foreach循环,并从未找到的项目创建新的列表

您可以使用LinqExcept扩展方法:

holidayDifference = remoteHolidays
    .Except(localHolidays)
    .ToList();

注意,这也需要Holiday实现一个有效的Equals method of IEquatable<Holiday>方法覆盖,而且GetHashCode必须为两个Holidays返回一个相同的哈希值,Equals返回true

此外,Except是一个返回(在这种情况下)IEnumerable<Holiday>的扩展,因此您必须使用ToList扩展方法才能检索List<Holiday>

或者,你可以使用other overload of Except,它允许你提供一个IEqualityComparer<Holiday>,而不是修改你的原始类。


strings例子:

List<string> holidayDifference = new List<string>();
List<string> remoteHolidays = new List<string> { "1", "2", "3" };
List<string> localHolidays = new List<string> { "1", "3" };
holidayDifference = remoteHolidays
    .Except(localHolidays)
    .ToList();
holidayDifference.ForEach(Console.WriteLine);

输出:

2


Holiday : IEquatable<Holiday>例子:

class Holiday : IEquatable<Holiday>
{
    public string Name { get; set; }
    public bool Equals(Holiday other)
    {
        return Name == other.Name;
    }
    // GetHashCode must return true whenever Equals returns true.
    public override int GetHashCode()
    {
        //Get hash code for the Name field if it is not null.
        return Name?.GetHashCode() ?? 0;
    }
}
public class Program
{
    public static void Main()
    {
        List<Holiday> holidayDifference = new List<Holiday>();
        List<Holiday> remoteHolidays = new List<Holiday>
        {
            new Holiday { Name = "Xmas" },
            new Holiday { Name = "Hanukkah" },
            new Holiday { Name = "Ramadan" }
        };
        List<Holiday> localHolidays = new List<Holiday>
        {
            new Holiday { Name = "Xmas" },
            new Holiday { Name = "Ramadan" }
        };
        holidayDifference = remoteHolidays
            .Except(localHolidays)
            .ToList();
        holidayDifference.ForEach(x => Console.WriteLine(x.Name));
    }
}

输出:

光明节

最简单的方法是使用LinQ。Except方法返回源中不存在于第二个列表中的所有项。

holidayDifference = remoteHolidays.Except(localHolidays).ToList();

Except方法接受第二个可选参数来定制比较。如果您没有通过IEqualityComparer<T>,则将使用与Holiday.Equals方法的标准比较。或者,您可以重写此方法,而不传递比较器。

像大多数LinQ方法一样,Except返回IEnumerable<T>,使用ToList方法可以很容易地将其转换为List<T>

MSDN文档是内联链接。


如果你仍然想自己实现这个,你可以使用List<T>Contains方法:

foreach (Holiday holiday in remoteHolidays)
{
    if (!localHolidays.Contains(holidy))
    {

Contains的替代方案是LinQs的Any,它允许您将对象与函数/lambda表达式进行比较。

假设您有一个Equals方法的重载并且Holiday对象是可比较的

List<Holiday> holidayDifference = remoteHolidays.Except(localHolidays).ToList();
private void updateHolidays()
{
    List<Holiday> localHolidays = getLocalHolidays();
    List<Holiday> remoteHolidays = getRemoteHolidays();
    List<Holiday> holidayDifference = new List<Holiday>();
    foreach (Holiday holiday in remoteHolidays)``
    {
        if (localHolidays.Contains(holiday)) 
        {
            // add holiday to holidayDifference
            holidayDifference.Add(holiday);
        }
    }
    createNewHolidays(holidayDifference);
}

如果您坚持foreach循环,您可以使用HashSet<Holiday>来存储Holiday s以排除:

HashSet<Holiday> hs = new HashSet<Holiday>(localHoliday);
foreach (Holiday holiday in remoteHolidays)
  if (!hs.Contains(holiday))
    holidayDifference.Add(holiday);

这取决于两个列表是否包含相同的Holiday对象,如果它们在两个列表中是相同的对象,那么你不需要制作一个实现IEqualityComparer的比较器。我将假设它们不是相同的对象,因此您是按值而不是按引用进行比较。

最快的方法是不使用foreach循环,您可以使用LINQ来完成此操作。

var holidayDifference = remoteHolidays.Except(localHolidays, new HolidaysComparer()).ToList();

如果你想使用foreach循环,你可以通过几种方式来实现。您可以使用HashSet(确保使用HolidayComparer初始化集合),通过迭代localHolidays中的值并将它们添加到集合中,然后从remoteHolidays中取出不在该集合中的值。然而,更简单的方法是使用LINQ的contains函数(上面的except函数实际上是将其封装到一个循环中)。

var holidayDifference = new List<Holiday>();
var comparer = new HolidayComparer();
foreach(Holiday holiday in remoteHolidays)
{
    if(!localHolidays.Contains(holiday, comparer)) 
        holidayDifference.Add(holiday);
}

如果你通过引用来比较每个假期,那么你不需要实现IEqualityComparer接口。

要了解如何实现这个接口,请查看这里的IEqualityComparer interface