比较两个列表中的项目并返回不匹配的项目

时间:2017-11-16 09:29:10

标签: c# list

所以我有两个列表。

List<Farmer> CSVFarmer;
List<Farmer> Farmers;

CSVFarmer List从一个读取csv文件的方法中获取其项目。

Farmers List从sql数据库中的表中获取其项目;

现在我要做的是比较两个列表并返回一个非匹配项列表;

例如,如果List CSVFarmer具有:

FarmerName     ContractNumber   ContactNumber
John           2468             12345
Mike           13579            15790

列表农民有:

FarmerName     ContractNumber   ContactNumber
Mike           13579            15790

返回的列表中只应包含一个项目:Farmer John。 农民阶层:

 public class Farmer:INotifyPropertyChanged
{
    int _id;
    string _firstName;
    string _farmerNo;
    string _contactNumber;

    public Farmer()
    {
        _firstName = string.Empty;
        _farmerNo = string.Empty;
        _contactNumber = string.Empty;
    }

    public int Id
    {
        get { return _id; }
        set
        {
            _id = value;
            OnPropertyChanged("Id");
        }
    }
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
        }
    }
    public string FarmerNo
    {
        get { return _farmerNo; }
        set
        {
            _farmerNo = value;
            OnPropertyChanged("FarmerNo");
        }
    }
    public string ContactNumber
    {
        get { return _contactNumber; }
        set
        {
            _contactNumber = value;
            OnPropertyChanged("ContactNumber");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged (string property)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

}

我试过这个:

public class vmUserManagement
{
public List<Farmer> Farmer { get; set; }
public List<Farmer> CSVFarmers { get; set; }
public List<Farmer> Farmers { get; set; }


public vmUserManagement()
    {
        CSVFarmers = new List<Farmer>();
        Farmers = new List<Farmer>();
        Farmer = new List<Farmer>();
   }

public List<Farmer> getAllFarmers()
    {
        Farmers = RepoDapper.getAllFarmers();
        return Farmers;
    }

public List<Farmer> CSVImportFarmer()
    {
        OpenFileDialog openFile = new OpenFileDialog();
        openFile.DefaultExt = ".csv";
        openFile.Filter = "(.csv) | *.csv";

        var browseFile = openFile.ShowDialog();
        if (browseFile == true)
        {
            string FilePath = openFile.FileName;
            List<Farmer> values = File.ReadAllLines(FilePath).Select(v => FromFarmerCsv(v)).ToList();
            CSVFarmers = values;
        }
        return CSVFarmers;
    }

 public static Farmer FromFarmerCsv(string csvLine)
    {
        string[] values = csvLine.Split(',');
        Farmer farmer = new Farmer();
        farmer.FirstName = values[0];
        farmer.FarmerNo = values[1];
        farmer.ContactNumber = values[2];
        return farmer;
    }


public List<Farmer> validateFarmerList()
    {


        foreach (var a in CSVFarmers)
        {
            foreach (var b in Farmers)
            {

                    if (a != b)
                    {
                        Farmer.Add(a);
                    }

            }
        }

        return Farmer;
    }
}

我遇到的问题是我最终会在List Farmer中输入两个条目。都是农夫约翰和农夫麦克。当我只得到一个包含Farmer John的List时。那是为什么?

我也尝试使用过:

 public List<Farmer> validateFarmerList()
    {           

        Farmer = CSVFarmers.Except(Farmers).ToList();
        return Farmer;
    }

但我仍然在我的农夫名单中找到两个项目(农夫约翰和迈克),而不是一个。 我错过了什么吗?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

您未在dash (-)课程中覆盖EqualsGethashCode。这就是为什么Farmer无法正常工作以及(a != b)失败的原因相同:仅引用进行比较且两者都是不同的实例。

.NET应该如何知道农民的Enumerable.Except与识别他有关?一个方法是通过覆盖ContractNumberEquals

来告诉它
GetHashCode

现在您可以使用public class Farmer : IEquatable<Farmer> { public string FarmerName { get; set; } public string ContractNumber { get; set; } // .... other properties etc public bool Equals(Farmer other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return string.Equals(ContractNumber, other.ContractNumber); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((Farmer) obj); } public override int GetHashCode() { return (ContractNumber != null ? ContractNumber.GetHashCode() : 0); } }

Except

第二种方法是实施自定义Farmer = CSVFarmers.Except(Farmers).ToList(); ,如果您无法更改IEqualityComparer<Farmer>类本身,或者您不想改变它的行为,只想要一个自定义比较器:

Farmer

您可以在许多LINQ方法中使用此比较器,例如也可以在public class FarmerContractComparer : IEqualityComparer<Farmer> { public bool Equals(Farmer x, Farmer y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(null, x) || ReferenceEquals(null, y)) return false; return x.ContractNumber == y.ContractNumber; } public int GetHashCode(Farmer obj) { return (obj.ContractNumber != null ? obj.ContractNumber.GetHashCode() : 0); } }public class FarmerContractComparer : IEqualityComparer<Farmer> { public bool Equals(Farmer x, Farmer y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(null, x) || ReferenceEquals(null, y)) return false; return x.ContractNumber == y.ContractNumber; } public int GetHashCode(Farmer obj) { return (obj.ContractNumber != null ? obj.ContractNumber.GetHashCode() : 0); } }

中使用
Enumerable.Except

这种方法的优点是可以为不同的任务提供不同的比较器。

第三种方法:使用LINQ并且不要创建新类(减少可重用性和效率,但减少工作量):

Farmer = CSVFarmers.Except(Farmers, new FarmerContractComparer()).ToList();

答案 1 :(得分:0)

您需要创建一个实现IEqualityComparer<Farmer>的类,并将其实例作为第二个参数传递给您的农民.Except() 实施IEquatable<Farmer>类。

另一个答案已经很好地实施了后者。如果总是希望农民在合同编号相等时保持平等,那就使用那个。

因此,如果您希望您的Except适用于合同号码,但在其他地方您需要其他条件,则需要第一个选项:

class FarmerEqualWhenContractEqualComparer : IEqualityComparer<Farmer>
{
    public bool Equals(Farmer x, Farmer y)
    {
        //Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        //Check whether the farmers' contracts are equal.
        return x.ContractNumber == y.ContractNumber;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public int GetHashCode(Farmer farmer)
    {
        //Check whether the object is null
        if (Object.ReferenceEquals(product, null)) return 0;

        //Get hash code for the Name field if it is not null.
        return farmer.ContractNumber?.GetHashCode() ?? 0;
    }
}

然后你可以这样做:

var changedOrNew = CSVFarmers.Except(Farmers, new FarmerEqualWhenContractEqualComparer()).ToList();