Melissa
Melissa

Reputation: 473

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?

Upvotes: 0

Views: 108

Answers (4)

Melissa
Melissa

Reputation: 473

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.

Upvotes: 0

ValGiv
ValGiv

Reputation: 1

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

Upvotes: 0

Salah Akbari
Salah Akbari

Reputation: 39946

Simply use Zip method in LINQ:

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

Upvotes: 1

PinBack
PinBack

Reputation: 2554

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.

Upvotes: 0

Related Questions