Search code examples
linqselectwhere-clauseaddrange

Using linq select a multiple price values


var filterModel = new List<FilterModel>()
{
    new FilterModel {Price = 1},
    new FilterModel {Price = 1},                
    new FilterModel {Price = 15},
    new FilterModel {Price = 20},
    new FilterModel {Price = 410},
    new FilterModel {Price = 9511},
    new FilterModel {Price = 9511},
    new FilterModel {Price = 252},
    new FilterModel {Price = 555},
    new FilterModel {Price = 602}
};

var priceList = new List<PriceList>
{
    new PriceList{MinPrice = 0,MaxPrice = 30},
    new PriceList{MinPrice = 70,MaxPrice = 130},
    new PriceList{MinPrice = 200,MaxPrice = 250},
    new PriceList{MinPrice = 400,MaxPrice = 600},
    //etc.etc. continue...
};

I have 2 models. I'm trying to use LINQ. My code is working. What would be the shortest (cleanest) way to do this?

var newFilterModel = new List<FilterModel>();

foreach (var t in priceList)
{
    newFilterModel.AddRange(filterModel
                               .Where(x => x.Price > t.MinPrice && x.Price < t.MaxPrice)
                               .ToList());
}
var distinctNewFilterModel = newFilterModel.Select(p=>new { p.Price})
                                           .Distinct().ToList();

Solution

  • I don't know if this is short & clean enough for you, but...

    var newFilterModel = filterModel
        // Select just the price
        .Select(f => f.Price)
        // Remove duplicates
        .Distinct()
        // Find prices in the price list
        .Where(price => priceList
            .FindIndex(p => p.MinPrice <= price && price <= p.MaxPrice) != -1)
        // Turn the price back into a FilterModel object
        .Select(price => new FilterModel { Price = price })
        // Turn the entire result into a new List<FilterModel>
        .ToList();
    
    newFilterModel.ForEach(newF => Console.WriteLine(newF.Price));
    

    Results:

    1
    15
    20
    410
    555
    

    If you were to implement IEquatable<> in your FilterModel class like this:

    public class FilterModel : IEquatable<FilterModel>
    {
        public int Price { get; set; }
    
        public bool Equals(FilterModel other)
        {
            //Check whether the compared object is null.
            if (ReferenceEquals(other, null)) return false;
    
            //Check whether the compared object references the same data.
            if (ReferenceEquals(this, other)) return true;
    
            //Check whether the products' properties are equal.
            return other.Price == Price;
        }
    
        public override int GetHashCode()
        {
            //Get hash code for the Price field.
            return Price.GetHashCode();
        }
    }
    

    Then your Linq statement gets shorter:

    var newFilterModel = filterModel
        // Remove duplicates
        .Distinct()
        // Find prices in the price list
        .Where(filterPrice => priceList
            .FindIndex(price => price.MinPrice <= filterPrice.Price && filterPrice.Price <= price.MaxPrice) != -1)
        // Turn the entire result into a List<FilterModel>
        .ToList();
    
    newFilterModel.ForEach(p => Console.WriteLine(p.Price));
    

    Results:

    1
    15
    20
    410
    555