Reputation: 473
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
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
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
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
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