How to properly get sum of dictionary values???

Hello to all, am I missing something here??? Developing an app that allow user to purchase items, need to be able to total all items in a cart like system.

I’m not able to get LINQ, system.c.g, and dictionary to work,

using Unity.Engine
using System.Collections.Generic
using System.LINQ

[SerializeField]
private float total;

Dictionary<string, float> purcahseItems = new Dictionary<string, float>;

  public class itemCalculation: MonoBehaviour
    {

void start()//on add
{

/// instead of start, this is where user will add items within app from UI, so items below will be displayed there
purcahseItems .Add (food, 13.99); // adds to dictionary
purcahseItems .Add (foodMore, 9.99); // adds to dictionary
}
public void Total()// on checkout
{
total = total +purchaseItems.Values.Sum();

}
}

I also put in “if” for when key overlap, being the same item gets purchased,??? but what about when same item gets purchased but one is edited,. should I assign these items with different key other than string?

If I run what I have the output will be 14.99, 13.99 plus one, same if I add another item, it would be 13.99 plus 2, so 15.99 instead of total of all values.

I see that’s happening but not sure how to correct it, items get added dynamically during run time from user, so I cannot pre allocate

Reason for dictionary is to store purchase data for order history

I’m looking to develop cart and checkout system

I aslo tried in a foreach block,…

Unity methods require they be capitalized to autorun properly. So “start” should be “Start”. As you have it, your start isn’t going to run so your dictionary is empty.

I would suggest using Debug.Log calls in the future to print out values, that will help you catch stuff like this in the future. :slight_smile:

here my original script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.Linq;
public class OrderManager : MonoBehaviour
{
    [SerializeField]
    private int BasketItems;
    [SerializeField]
    private int ItemQuanity;
    [SerializeField]
    private TMP_Text ItemQuanityGo;
    [SerializeField]
    private TMP_Text BasketGo;
    [SerializeField]
    private int BasketEmpty;
    [SerializeField]
    private int ItemOrderNumber;
    [SerializeField]
    private float initScale = 1.0f;
    [SerializeField]
    private NetworkManager nwm;
    [SerializeField]
    private GameObject ItemPrefab;
    [SerializeField]
    private Transform ItemPrefabContainer;
    [SerializeField]
    private Product productData;
    [SerializeField]
    private float Total;
    [SerializeField]
    private TMP_Text TotalGo;
    [SerializeField]
    private Dictionary<int,float> subtotals= new Dictionary<int,float>();
    [SerializeField]
    private Dictionary<string, float> sums = new Dictionary<string, float>();
    //

    public void orderCalculation(TMP_Text itemQuanityGo)
    {
        ///take in itemGo
        ///take in product script
        ////take in product network manager
        ItemQuanityGo = itemQuanityGo;
        nwm = ItemQuanityGo.gameObject.GetComponentInParent<NetworkManager>()as NetworkManager;
        productData= ItemQuanityGo.gameObject.GetComponentInParent<Product>() as Product;
        addToCart();

    }
    public void orderCal()
    {
        Debug.Log(subtotals.Count());
       // Total = subtotals.Count();
        foreach (float subT in subtotals.Values)
        {
            Total = Total + subtotals.Values.Sum();
          
           // Total += subT.Value;
           
        }

       // Total = subtotals.Sum(s => subtotals[s]); Debug.Log(Total);
       
       

        //Debug.Log(Total);
        TotalGo.text = " TOTAL: $" + Total.ToString();



    }
    public void orderCalMinus()
    {
      

    }
    public void addToCart()
    {
        BasketItems+= ItemQuanity;
        BasketGo.text = BasketItems.ToString();

        //instantiate prefab item container
        //pass values to Item Name , SubTotal,
        //set edit button to active in cart and checkout butoon to active in options tab on menu
        //set remove button to active on cart

        for (int i = 0; i < ItemQuanity; ++i)
        {
            var myNewItem = Instantiate(ItemPrefab, new Vector3(i * transform.position.x, transform.position.y, transform.position.z), Quaternion.identity);
            myNewItem.transform.SetParent(ItemPrefabContainer.transform);
            myNewItem.transform.localScale = new Vector3(initScale, initScale, initScale);

            string productNameTemp = "" + productData.ImageSourceName;
            float productSubTotal = productData.ImageSourceCost;



            GameObject myNewItemName = myNewItem.transform.GetChild(1).gameObject; Debug.Log(myNewItemName);//name
            myNewItemName.GetComponent<TextMeshProUGUI>().text = " " + productNameTemp; Debug.Log("" + productNameTemp);

            ////////////////////////////////////////////////////////////////////////////////////////////////////////

            GameObject myNewItemSubt = myNewItem.transform.GetChild(2).GetChild(0).gameObject; Debug.Log(myNewItemSubt);//subtotal
            myNewItemSubt.GetComponent<TextMeshProUGUI>().text = "SUBTOTAL: " + productSubTotal; Debug.Log(productSubTotal);

            if (subtotals.ContainsKey(ItemOrderNumber))
            {

                subtotals[ItemOrderNumber]++;

            }
            else
            {
             subtotals.Add(ItemOrderNumber, productSubTotal);
           
            }
          

        }

    }
  
    public void updatePrice() // update gui price
    {
        ItemQuanity = 1;
        float moreCost = nwm.ImageCost * ItemQuanity;
        nwm.srcCost.text = "$" + moreCost.ToString("f2");

    }
    public void removecart() // update cart after item removed
    {
        ItemQuanity--;
        BasketItems--;
        string productNameTemp = productData.ImageSourceName;
        float productSubTotal = productData.ImageSourceCost;

        if (ItemQuanity <= 0)
            ItemQuanity = 0;
        BasketGo.text = BasketItems.ToString();
        if (ItemQuanity == 0)
        {
            ItemQuanity = 1;

        }
        if (subtotals.ContainsKey(ItemOrderNumber))
        {

            subtotals[ItemOrderNumber]--;
        }
        else
        {
            subtotals.Remove(ItemOrderNumber);

        }

    }
    public void add(TMP_Text itemQuanityGo) /// gui ui on menu
    {
        ItemQuanityGo = itemQuanityGo;
        nwm = ItemQuanityGo.gameObject.GetComponentInParent<NetworkManager>() as NetworkManager;
        productData = ItemQuanityGo.gameObject.GetComponentInParent<Product>() as Product;
    
    
                if (ItemQuanity<99)
        {
         
            ItemQuanity++;
            float moreCost = nwm.ImageCost * ItemQuanity;
            nwm.srcCost.text = "$" + moreCost.ToString("f2");
            if (ItemQuanity >= 99)
            {
                ItemQuanity = 99;
                // contact shop
            }

        }
   
   
    }
    public void minus() /// gui ui on menu
    {

        if (ItemQuanity>0)
        {
         
            ItemQuanity--;
            float moreCost = nwm.ImageCost *ItemQuanity;
            nwm.srcCost.text = "$" + moreCost.ToString("f2");
            if (ItemQuanity==0)
            {
                ItemQuanity = 1;
                nwm.srcCost.text = "$" + nwm.ImageCost.ToString("f2");
            }
        }

    }
    // Start is called before the first frame update
    void Start()
    {
        ItemQuanity = 1;
      
    }

    // Update is called once per frame
    void Update()
    {
        ItemQuanityGo.text = ItemQuanity.ToString();
    }
}

Is there A way to jus t add items to a list then total the list and use that same list for purchase history, or should I make use of scriptable objects here?

MyList.Add(item);
int total = 0;
foreach( var item in MyList)
{
  total += item;
}

I don’t know what that means in your context.

Are you making predefined data as assets on disk? If not, I doubt scriptable objects have anything to do with your reality.

hmmm, the code output gives me
SUM
Total = "value + count(as if it was value) + count(as if it was value) " ,

ex(5.99, 1(item), 1(item))

sum output I’m getting = 7.99

instead of

ex(5.99, 8.99, .99)
sum output should print = 15.97

SUM
Total = "value +value + value " ,

what’s happening is my code sum function is only taking the first value and then the remaining items as count, but all values is needed.

As seen in “orderCal” code block lines 52-62 I’m using this code line

" Total = Total + subtotals.Values.Sum(); "

but I also used this code line

" Total += subT.Value; "

still didn’t work for me

also tried " Total += subT.Value.Sum(); " outside the foreach block and that didn’t work either,
been at it for little over a week now.

desired results: when user press checkout button, then user will get total of all values added to user cart for next step(make purchase), user cannot make purchase without proper Total …

Thanks,

Your original source unfortunately doesn’t make sense (e.g.:

        foreach (float subT in subtotals.Values)
        {
            Total = Total + subtotals.Values.Sum();
        
           // Total += subT.Value;
          
        }

what is subtotals.Values.Sum, and why are you adding it every time through the loop, and why aren’t you using the iterator subT? Are you sure you know what you are doing?

And I can’t make heads nor tails from your last post. Why don’t you post your current code, and the data set you are operating on? That would make things much easier.

Also, if you want to create a purchase history, you may want to look into tuples. They can make short work of this problem, with the key being a simple index what item, and all the remaining items being data like product (string), price (float) and maybe even purchase date.

I just threw this into a script real quick and I got 9.99, so it’s not having issues that way.

        Dictionary<int, float> test = new Dictionary<int, float>();
        test.Add(1, 1.99f);
        test.Add(2, 5);
        test.Add(3, 3);
        float tot = 0;
        tot = test.Values.Sum();
        Debug.Log(tot);

Also, as @csofranz mentioned, if you just want to loop through, you should be looping through and adding each while one at a time. By doing the sum per value, I would end up with 29.97. The point of Sum is to add all the values together.

@csofranz I did post current code, third post here, that’s where I paused for a sec after tinkering with it, listen apologies I’m not the smartest man in the world, I know what I need to get done and how to go about it somewhat.

I Was making light work within my skill until I reached checkout haha…

when it didn’t work I tried several different lines and blocks to see what I was missing, again not the ultimate programmer, that’s why after trying and failing for over a week, I posted here to get help with this solution.

Also, my understanding is with LINQ I should be able to use simple SUM() without iterating loop. I keep troubleshooting and trying.

here’s my code without foreach this time still not working for me. And @csofranz that is the intended direction – what you mentioned with purchase history, but I don’t have they level of skill just yet…

Also inserted pictorial reference,

as seen in images I’m not getting total, it’s doing something else, am I going wrong in addToCart block starting at line 71???
@Brathnann also thanks again

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.Linq;
public class OrderManager : MonoBehaviour
{
    [SerializeField]
    private int BasketItems;
    [SerializeField]
    private int ItemQuanity;
    [SerializeField]
    private TMP_Text ItemQuanityGo;
    [SerializeField]
    private TMP_Text BasketGo;
    [SerializeField]
    private int BasketEmpty;
    [SerializeField]
    private int ItemOrderNumber;
    [SerializeField]
    private float initScale = 1.0f;
    [SerializeField]
    private NetworkManager nwm;
    [SerializeField]
    private GameObject ItemPrefab;
    [SerializeField]
    private Transform ItemPrefabContainer;
    [SerializeField]
    private Product productData;
    [SerializeField]
    private float Total;
    [SerializeField]
    private TMP_Text TotalGo;
    [SerializeField]
    private Dictionary<int,float> subtotals= new Dictionary<int,float>();
    [SerializeField]
    private Dictionary<string, float> sums = new Dictionary<string, float>();
    //

    public void orderCalculation(TMP_Text itemQuanityGo)
    {
        ///take in itemGo
        ///take in product script
        ////take in product network manager
        ItemQuanityGo = itemQuanityGo;
        nwm = ItemQuanityGo.gameObject.GetComponentInParent<NetworkManager>()as NetworkManager;
        productData= ItemQuanityGo.gameObject.GetComponentInParent<Product>() as Product;
        addToCart();

    }
    public void orderCal()
    {
        Debug.Log(subtotals.Count());
       // Total = subtotals.Count();
        Total += subtotals.Values.Sum();

        //
        TotalGo.text = " TOTAL: $" + Total.ToString();
        Debug.Log(Total);



    }
    public void orderCalMinus()
    {
 

    }
    public void addToCart()
    {
        BasketItems+= ItemQuanity;
        BasketGo.text = BasketItems.ToString();

        //instantiate prefab item container
        //pass values to Item Name , SubTotal,
        //set edit button to active in cart and checkout butoon to active in options tab on menu
        //set remove button to active on cart

        for (int i = 0; i < ItemQuanity; ++i)
        {
            var myNewItem = Instantiate(ItemPrefab, new Vector3(i * transform.position.x, transform.position.y, transform.position.z), Quaternion.identity);
            myNewItem.transform.SetParent(ItemPrefabContainer.transform);
            myNewItem.transform.localScale = new Vector3(initScale, initScale, initScale);

            string productNameTemp = "" + productData.ImageSourceName;
            float productSubTotal = productData.ImageSourceCost;



            GameObject myNewItemName = myNewItem.transform.GetChild(1).gameObject; Debug.Log(myNewItemName);//name
            myNewItemName.GetComponent<TextMeshProUGUI>().text = " " + productNameTemp; Debug.Log("" + productNameTemp);

            ////////////////////////////////////////////////////////////////////////////////////////////////////////

            GameObject myNewItemSubt = myNewItem.transform.GetChild(2).GetChild(0).gameObject; Debug.Log(myNewItemSubt);//subtotal
            myNewItemSubt.GetComponent<TextMeshProUGUI>().text = "SUBTOTAL: " + productSubTotal; Debug.Log(productSubTotal);

            if (subtotals.ContainsKey(ItemOrderNumber))
            {

                subtotals[ItemOrderNumber]++;

            }
            else
            {
             subtotals.Add(ItemOrderNumber, productSubTotal);
 
            }
 

        }

    }
 
    public void updatePrice() // update gui price
    {
        ItemQuanity = 1;
        float moreCost = nwm.ImageCost * ItemQuanity;
        nwm.srcCost.text = "$" + moreCost.ToString("f2");

    }
    public void removecart() // update cart after item removed
    {
        ItemQuanity--;
        BasketItems--;
        string productNameTemp = productData.ImageSourceName;
        float productSubTotal = productData.ImageSourceCost;

        if (ItemQuanity <= 0)
            ItemQuanity = 0;
        BasketGo.text = BasketItems.ToString();
        if (ItemQuanity == 0)
        {
            ItemQuanity = 1;

        }
        if (subtotals.ContainsKey(ItemOrderNumber))
        {

            subtotals[ItemOrderNumber]--;
        }
        else
        {
            subtotals.Remove(ItemOrderNumber);

        }

    }
    public void add(TMP_Text itemQuanityGo) /// gui ui on menu
    {
        ItemQuanityGo = itemQuanityGo;
        nwm = ItemQuanityGo.gameObject.GetComponentInParent<NetworkManager>() as NetworkManager;
        productData = ItemQuanityGo.gameObject.GetComponentInParent<Product>() as Product;
 
 
                if (ItemQuanity<99)
        {
 
            ItemQuanity++;
            float moreCost = nwm.ImageCost * ItemQuanity;
            nwm.srcCost.text = "$" + moreCost.ToString("f2");
            if (ItemQuanity >= 99)
            {
                ItemQuanity = 99;
                // contact shop
            }

        }
 
 
    }
    public void minus() /// gui ui on menu
    {

        if (ItemQuanity>0)
        {
 
            ItemQuanity--;
            float moreCost = nwm.ImageCost *ItemQuanity;
            nwm.srcCost.text = "$" + moreCost.ToString("f2");
            if (ItemQuanity==0)
            {
                ItemQuanity = 1;
                nwm.srcCost.text = "$" + nwm.ImageCost.ToString("f2");
            }
        }

    }
    // Start is called before the first frame update
    void Start()
    {
        ItemQuanity = 1;
 
    }

    // Update is called once per frame
    void Update()
    {
        ItemQuanityGo.text = ItemQuanity.ToString();
    }
}

            if (subtotals.ContainsKey(ItemOrderNumber))
            {
                subtotals[ItemOrderNumber]++;
            }
            else
            {
             subtotals.Add(ItemOrderNumber, productSubTotal);
            }

You add the order number and the cost of that product to subtotals when you add a product.
But if you add another product, you increment the subtotal by 1??? Is it supposed to count the price, or the quantity? You are doing both here.

That is why you are getting 19.99. The first Lamb Chops you add sets the first element of subtotals to 16.99. Then the next 3 things you add to your order just adds 1. 16.99 + 3 = 19.99.

ItemOrderNumber never changes, so your summing of the subtotals dict is pointless because your subtotals only ever contains one element anyway.

I would suggest going back and completely rethinking what exactly the subtotals dictionary is supposed to be.

There was actually never any problem with summing a dictionary in the first place.

What was suppose to happen there is if the same item gets added, if I remove that then I get error already contains key…if I add same item twice, also how is this happening when the key is different for the other item?

also total is asking for values, 2 keys where the same one was different, subtotals have keys and values, we just need total of all values - the count was off, even with two different keys in container(dictionary)

So you added that code blindly just to make an error go away without understanding whats going on?

You can’t add multiple entries to a dictionary with the same key, that’s just not how dictionaries are supposed to work. I would suggest reading up on C# dictionaries to gain a better understanding of how they are supposed to be used.

If you just want to add the cost of the new item, then actually add the cost of the new item, instead of incrementing the subtotal by 1.

            if (subtotals.ContainsKey(ItemOrderNumber))
            {
                subtotals[ItemOrderNumber] += productSubTotal;
            }
            else
            {
             subtotals.Add(ItemOrderNumber, productSubTotal);
            }

Nothing in your code ever changes the key, ItemOrderNumber

Didn’t add blindly, else block changes the key in this situation(thinking), in pictures it shows where the first two items fall under ++ line same item , yet the last item is something different it doesn’t contain same key, or are you saying the else never gets executed , again not the ultimate programmer

we also need that same item to get added twice, one maybe with edits,

I’m working through the situation

The key is ItemOrderNumber, and not a single line of code changes that variable. Additionally, it is a private variable, so no external script can modify it either.

Your code is doing this:

The first item you add will execute the else block, since the dictionary is empty. It will then put the cost of that item in the dictionary (16.99).

Each item you add after that will execute the if block, and will simply increment that cost by 1 (17.99, 18.99, 19.99).

just seen just seen and you helped thanks much you got it, I thought when it add in first if block it would get added, had one small thought one that and left it alone and went down a long journey, nice, also in removal

subtotals[ItemOrderNumber] -= productSubTotal;

sometimes you work so long you can out work yourself, breaks is needed and fresh eyes sometimes

After working on some things a bit, now im here,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using TMPro;
using System;

public class _Dictionary : MonoBehaviour
{
    [SerializeField]private removeItem _rm;
   
    private double temp = 0;

    public readonly Dictionary<orderItems, double> _dictionary = new Dictionary<orderItems, double>(new orderItems.EqualityComparer());
    public orderItems oItems = new orderItems("", 1);

  


    public int itemSpacetotal = 0;

    public class orderItems
    {
        private string name;
        private int iid;

        public string iname {
            get { return name; }
            private set { name = value; }
        }
        public int iId {
            get { return iid; }
            private set { iid = value; }
        }
        public class EqualityComparer : IEqualityComparer<orderItems>
        {

            public bool Equals(orderItems x, orderItems y)
            {
                return x.name == y.name && x.iid == y.iid;
            }

            public int GetHashCode(orderItems x)
            {
                return x.name.GetHashCode() ^ x.iid.GetHashCode();
            }

        }


        public orderItems(string iName, int iId)
        {
            name = iName;
            iid = iId;
        }

    }

    public void Awake()
    {
        temp = _dictionary.Values.Sum();
    
    }
    public void ADDTO(string oi, double d)
    {
        var oI = new orderItems(oi, itemSpacetotal + 1);
        _dictionary.Add(oI, d);
        itemSpacetotal++;
        foreach (var ver in _dictionary.ToList())
        {
            temp = _dictionary.Values.Sum();
         
        }
    }
    public void REMOVEFROM(int i)
    {
        itemSpacetotal--;
        foreach (var ver in _dictionary.Where(kvp => kvp.Key.iId == i).ToList())
        {
            _dictionary.Remove(ver.Key);
             temp = _dictionary.Values.Sum();
        
        }
    }
    public int returnId(string n, double d)
    {
        int idNum = 0;
        foreach (var ier in _dictionary.Where(kvp => kvp.Key.iname == n  ).ToList().Where(kvp => kvp.Value == d).ToList())
        {
             idNum = ier.Key.iId;
        }
        return idNum;
    }
    public double sumAll()
    {
        double s = _dictionary.Values.Sum();
        return s;
    }
    public void clearAll()
    {
       _dictionary.Clear();
       
    }

}