Reputation: 18068
I have list of cars and list of rentals of those cars. Every rental has DateTime From
and DateTime To
and Car Car
properties.
I would like to exclude from list of cars, those cars which are unavailable at the chosen period. The beginning and end of this period are values of two DateTimePickers
.
I achieved my goal by this code:
public void FilterAvailableCars() {
List<Car> cars = ObjectPlus.Objects[typeof(Car)].Select(o => (Car)o).ToList();
List<Rental> rentals = ObjectPlus.Objects[typeof(Rental)].Select(r => (Rental)r).ToList();
foreach (var rent in rentals) {
if (fromDateTimePicker.Value < rent.To && rent.From < toDateTimePicker.Value) {
cars.Remove(rent.Car);
}
}
carListBox.DataSource = cars;
}
I mixed LINQ and for loops, but I would like to know how pure and efficient LINQ solution would look like.
Upvotes: 0
Views: 88
Reputation: 205589
The most efficient way usually is to correlate the data using join
(or antijoin like in your case):
var rentals = ObjectPlus.Objects[typeof(Rental)].Cast<Rental>()
.Where(rent => fromDateTimePicker.Value < rent.To && rent.From < toDateTimePicker.Value);
carListBox.DataSource =
(from car in ObjectPlus.Objects[typeof(Car)].Cast<Car>()
join rent in rentals on car equals rent.Car into carRentals
from carRent in carRentals.DefaultIfEmpty()
where carRent == null
select car).ToList();
Upvotes: 1
Reputation: 21999
Few fixes:
// filter rentals within entered date
var rentals = ObjectPlus.Objects[typeof(Rental)].Cast<Rental>()
.Where(rent => fromDateTimePicker.Value < rent.To && rent.From < toDateTimePicker.Value);
// filter rented cars
carListBox.DataSource = ObjectPlus.Objects[typeof(Car)].Cast<Car>()
.Where(car => !rentals.Any(rent => rent == car)).ToList();
Use Cast/OfType
and do filtering with single Where
(creating list and removing items from it as you do is kind of inefficient).
I don't know how efficient is Except
, if you don't instantiate query result (using ToList()
) then it should be same efficient.
It may be more efficient (depending on number of items of Rental
and Car
) to check for cars inside rental's Where
.
Upvotes: 1
Reputation: 75306
First, you select all the rental cars based your condition:
var rentalCars = rentals.Where(rent =>
fromDateTimePicker.Value < rent.To && rent.From < toDateTimePicker.Value)
.Select(r => r.Car);
Then, use Except
method to get the result:
carListBox.DataSource = cars.Except(rentalCars);
Upvotes: 1