简体   繁体   中英

Compare a property of an object in 2 lists

I have the following (simplified) class:

public class CareRate {

  [Key]
  public int Id { get; set; }
  public string Description { get; set; }
  public decimal DayRate { get; set; }
}

I would like to compare two lists of CareRate only by their DayRate ; one with CareRates containing the current DayRates and one with CareRates containing the DayRates to update. Other properties which might have changed like Description, should not be taken into account.

// Just a test method
public List<CareRate> FilterChangedCareRates(){
    var currentCareRates = new List<CareRate>{
        new CareRate { Id = 1, DayRate = 3,33, Description = "Some descr" }, 
        new CareRate { Id = 2, DayRate = 4,44, Description = "Some other descr" } 
    };

    var updatedCareRates = new List<CareRate>{
        new CareRate { Id = 1, DayRate = 2,22 }, 
        new CareRate {Id = 2, DayRate = 4,44 } // Unchanged
   };

    var actualUpdatedCareRates = new List<CareRate>();

    foreach(var updatedCareRate in updatedCareRates) {
        var currentCareRate = currentCareRates.Single(x => x.Id == updatedCareRate.Id); 
        if (updatedCareRate.DayRate != currentCareRate.DayRate) {
            actualUpdatedCareRates.Add(updatedCareRate); 
        }
    }
    return actualUpdatedCareRates;
}

The manner to filter the changed CareRate objects by Dayrate , feels a bit devious. I think I am overlooking something. What other and better options are there for acquiring the above?

Simply use Zip method in LINQ:

var actualUpdatedCareRates = currentCareRates.Zip(updatedCareRates, 
                             (f, s) => f.DayRate != s.DayRate ? s : null)
                             .Where(c => c != null).ToList();

I think, you can use something like this:

updatedCareRates.ForEach(x =>
{
    if (currentCareRates.FirstOrDefault(y => y.Id == x.Id && y.DayRate != x.DayRate) != null)
        actualUpdatedCareRates.Add(x);
});

Or in one line:

updatedCareRates.Where(x => currentCareRates.FirstOrDefault(y => y.Id == x.Id &&
                            y.DayRate != x.DayRate) != null).ToList()
                           .ForEach(x => actualUpdatedCareRates.Add(x));

You can use this:

return (from up in updatedCareRates
            join cur in currentCareRates
            on up.Id equals cur.Id
            where up.DayRate != cur.DayRate
            select up).ToList();

Here is one of the rare cases where I think Query syntax is better than Method syntax.

Instead of using an Where(x => x...) , I looked for a solution with using the Except method as posted here .

I created a class DayRateComparer as showed below.

public class DayRateComparer : IEqualityComparer<CareRate>
{
    public bool Equals(CareRate x, CareRate y) {
        if (x = null) throw new ArgumentNullException(nameof(x));
        if (y = null) throw new ArgumentNullException(nameof(y));

        return x.Id == y.Id && x.DayRate == y.DayRate;
    }

    public int GetHashCode(CareRate obj) {
        retun obj.Id.GetHashCode() + obj.DayRate.GetHashCode(); 
    }
}

And I used the DayRateComparer like this:

// Just a test method
public List<CareRate> FilterChangedCareRates(){
    var currentCareRates = new List<CareRate>{
        new CareRate { Id = 1, DayRate = 3,33, Description = "Some descr" }, 
        new CareRate { Id = 2, DayRate = 4,44, Description = "Some other descr" } 
    };

    var updatedCareRates = new List<CareRate>{
        new CareRate { Id = 1, DayRate = 2,22 }, 
        new CareRate {Id = 2, DayRate = 4,44 } // Unchanged
   };

    return updatedCareRates.Except(currentCareRates, new DayRateComparer()).ToList();
}

I don't like the use of a temporary list (like actualUpdatedCareRates ) and this is not necessary anymore when using a comparer. The Zip method as mentioned by @S.Akbari is also a clean and short way but looks a bit complex for me at first sight. Thanks all for your posts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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