Guilherme Oderdenge
Guilherme Oderdenge

Reputation: 5001

How to calculate the final price of each product within a List<T>?

The goal

Calculate the final price of each product within a List<T> of C#.

The problem

I need to calculate price * quantity of a simple product and return the result to the view.

Look this syntax:

var productPrice = productsPrices.Find(x => x.productId == 1); 
productPrice.finalProductPrice = 
    (productPrice.promotionalProductPrice != 0 ? 
        productPrice.promotionalProductPrice : 
        productPrice.originalProductPrice) 
    * sessionProducts.Find(x => x.id == 1).quantity;

Just before of code fragment passed above, there is a string that stores the ids of the products, see:

string ids = string.Join(", ", sessionProducts.Select(x => x.id));

And I think that I need it to set a value to finalProductPrice of each product of my productsPrices list, but I don't know how I can perform this.

What I thought about this subject:

I had thought that I could use something like this:

productsPrices.Find(x => x.productId == productsPrices.Contains(ids))
    .finalProductPrice = 
    (productsPrices.Find(x => productsPrices.Contains(ids))
        .promotionalProductPrice != 0 ?
    productsPrices.Find(x => productsPrices.Contains(ids))
        .promotionalProductPrice : 
    productsPrices.Find(x => productsPrices.Contains(ids))
        .originalProductPrice) *
    sessionProducts.Find(x => x.id == 1).quantity;

But, of course, no success — .Contains() doesn't work with strings.

My real question

How can I define the right finalProductPrice for each product that my productsPrices list has? How can I pass each id within string ids [...] to x.productId == something?

Hints will be welcome (E.g. don't use .Find(), use .Select() instead!)

Spotlight code

Follow my ActionResult that sends all the necessary information to my view:

Compare.cs:

public ActionResult Compare()
{
    List<getMarkets_Result> markets = Markets.Build();

    SessionStore sessionStore = new SessionStore();
    List<getSpecificProductToShoppingList_Result> sessionProducts = 
        sessionStore.Get("ProductsSummary", "generic");

    string ids = string.Join(", ", sessionProducts.Select(x => x.id));
    List<getProductsPrices_Result> productsPrices = Products.PricesList(ids);

    ListComparisonViewModel listComparisonViewModel = 
       new ListComparisonViewModel
    {
        Markets = markets,
        SessionProducts = sessionStore.Get("ProductsSummary", "generic"),
        ProductsPrices = productsPrices
    };

    return View(listComparisonViewModel);
}

If necessary, the context of my productsPrice list:

public partial class getProductsPrices_Result
{
    public decimal originalProductPrice { get; set; }
    public decimal promotionalProductPrice { get; set; }
    public decimal finalProductPrice { get; set; }
    public string productName { get; set; }
    public string marketName { get; set; }
    public int productId { get; set; }
    public int marketId { get; set; }
}

And I made a model called Products(.cs) to perform the logic behind of the products. The first (and single) method that this model has is CalculateFinalPrice():

public decimal CalculateProductPriceByQuantity(decimal price, int quantity)
{
    return price * quantity;
}

Upvotes: 5

Views: 7544

Answers (4)

Jay
Jay

Reputation: 6294

I think you should conciser creating a model that represents your data in a way that will make your business problem easier to solve. In other words, make the code work to solve you solution.

Firstly the product should not know about the quantity. Assuming this works like a cart, the product should only know about itself. So the implementation of finalProductPrice should be much easier:

public decimal finalProductPrice 
{
    get 
    {
        return (promotionalProductPrice != 0 ? 
            promotionalProductPrice : 
            originalProductPrice);
    }
}

When working with your products, create a class and contain them in that to calculate the quality and total price:

public class ProductCollection
{
    public IEnumerable<getProductsPrices_Result> Products { get; set; }
    public int Quantity { get { return Products.Count; } }
    public decimal TotalPrice 
    {
        get
        {
            return Products.Sum(p => p.finalProductPrice );
        }
    }
    public ProductCollection(IEnumerable<getProductsPrices_Result> products)
    {
        this.Products = products;
    }
}

Now your viewmodel can look something like this:

ListComparisonViewModel
{
    Markets = markets,
    Products = new ProductCollection(sessionStore.Get("ProductsSummary", "generic"))
};

One important note I would like to make here is this helps to reduce your session access surface area. Session can be "accessed by anyone" and thus can become discombobulated and cause lots of issues down the road. In almost all scenarios fewer hands in the session cookie jar the better. (fewer keys as well as fewer class types and instances)

Upvotes: 1

Raciel R.
Raciel R.

Reputation: 2156

  • I would double check your class design.
  • I would make promotionalPrice nullable, what if you need price = 0 for a promotion?
  • Consider making this an extension method for the collection of products references in session.

With what I have at hand:

foreach(var product in sessionProducts){        
    var productPrice == productPrices.FirstOrDefault(p=>p.ProductId == product.id);
    var price = 0;
    if (productPrice != null)
       price = productPrice.promotionalPrice == 0 ? productPrice.originalPrice : productPrice.promotionalPrice;

    product.finalPrice = product.Qty * price;
}

Upvotes: 0

Konstantin
Konstantin

Reputation: 3294

question is a bit fuzzy but looks like you may be looking for something like following

var res = (from p in products
           from s in sessionproducts
           where p.id == s.id
           select new Product() { id = p.id, finalprice = s.qty * (p.promoprice > 0 ? p.promoprice : p.price) })
           .ToList();

Upvotes: 0

devdigital
devdigital

Reputation: 34349

You've got a lot of issues here. Firstly, your properties should be PascalCase, not camelCase. Secondly, your class is poorly named. getProductsPrices_Result shouldn't be prefixed with a verb, and it should be PascalCase with no underscores.

Aside from that, you have a lot of redundant code. The FinalProductPrice doesn't sound like an appropriate property for a Product type.

To answer the question about getting a collection of products that match a collection of ids, you can use LINQ:

string[] ids = ...;
List<Product> products = ...;

List<Product> matchingProducts = 
    products.Where(p => ids.Any(i => i == p.Id)).ToList();

Upvotes: 0

Related Questions