Home > Blockchain >  C# occurrence counting generic list with different property types
C# occurrence counting generic list with different property types

Time:11-22

I need to count the occurrences of each element in the "ID" field of a generic list. The result should be the list with an added field called "Quantity".

Suppose the following class is used for the list:

public class InfoList
{
  public string ID { get; set; }            
  public DateTime PurchaseDate { get; set; }
  public double Amount { get; set; }
  public int Quantity { get; set; }
}

Imagine an initial list like the following:

ID Purchase date Amount (USD)
DDD 30 jul 2025 258,225.11
AXC 10 nov 2023 982,383.95
AXC 12 feb 2031 -439,130.87
TPV 05 mar 2023 439,715.32
DDD 8 apr 2024 -153,893.38
KYR 24 mar 2023 -153,893.38
AXC 10 sep 2026 638,031.66
SPM 26 oct 2023 -401,815.59
DDD 08 mar 2023 -315,099.43
HGP 30 nov 2025 -474,749.80
DDD 02 jul 2024 -253,726.59
NDS 06 sep 2029 490,035.01
HGP 24 dec 2026 468,006.38

The final result should be the following:

ID Purchase date Amount (USD) Quantity
DDD 30 jul 2025 258,225.11 4
AXC 10 nov 2023 982,383.95 3
AXC 12 feb 2031 -439,130.87 3
TPV 05 mar 2023 439,715.32 1
DDD 8 apr 2024 -153,893.38 4
KYR 24 mar 2023 -153,893.38 1
AXC 10 sep 2026 638,031.66 3
SPM 26 oct 2023 -401,815.59 1
DDD 08 mar 2023 -315,099.43 4
HGP 30 nov 2025 -474,749.80 2
DDD 02 jul 2024 -253,726.59 4
NDS 06 sep 2029 490,035.01 1
HGP 24 dec 2026 468,006.38 2

Result should be of type "InfoList" not in a different list or variable.

CodePudding user response:

If I'm understanding this correctly, you can track quantities in a dictionary as a separate data structure.

void main()
{
  List<ItemList> purchaseList = buildItemList();
  Dictionary<string,int> quantity = buildQuantityDictionary(purchaseList);
  printTable(purchaseList, quantity);
}

List<ItemList> buildItemList()
{
  //however you build the itemlist
}

Dictionary<string,int> buildQuantityDictionary(List<ItemList> purchaseList)
{
  Dictionary<string,int> quantity = new Dictionary<string,int>();
  foreach(ItemList item in purchaseList)
  {
    if(!quantity.ContainsKey(item.id))
    {
      quantity.add(item.id,0);
    }
    quantity[item.id]  ;
  }
  return quantity;
}

void printTable(List<ItemList> purchaseList, Dictionary<string,int> quantity)
{
  foreach(ItemList item in purchaseList)
  {
    //You'll need to write a ToString() override for your ItemList object.
    Console.WriteLine($"{item.ToString()},{quantity[item.id]}");
  }
}

CodePudding user response:

Here's an approach that preserves the original order of the list.

var initial = new[]
{
    new { ID = "DDD", PurchaseDate = DateTime.Parse("30 jul 2025"), Amount = 258225.11 },
    new { ID = "AXC", PurchaseDate = DateTime.Parse("10 nov 2023"), Amount = 982383.95 },
    new { ID = "AXC", PurchaseDate = DateTime.Parse("12 feb 2031"), Amount = -439130.87 },
    new { ID = "TPV", PurchaseDate = DateTime.Parse("05 mar 2023"), Amount = 439715.32 },
    new { ID = "DDD", PurchaseDate = DateTime.Parse("8 apr 2024"), Amount = -153893.38 },
    new { ID = "KYR", PurchaseDate = DateTime.Parse("24 mar 2023"), Amount = -153893.38 },
    new { ID = "AXC", PurchaseDate = DateTime.Parse("10 sep 2026"), Amount = 638031.66 },
    new { ID = "SPM", PurchaseDate = DateTime.Parse("26 oct 2023"), Amount = -401815.59 },
    new { ID = "DDD", PurchaseDate = DateTime.Parse("08 mar 2023"), Amount = -315099.43 },
    new { ID = "HGP", PurchaseDate = DateTime.Parse("30 nov 2025"), Amount = -474749.80 },
    new { ID = "DDD", PurchaseDate = DateTime.Parse("02 jul 2024"), Amount = -253726.59 },
    new { ID = "NDS", PurchaseDate = DateTime.Parse("06 sep 2029"), Amount = 490035.01 },
    new { ID = "HGP", PurchaseDate = DateTime.Parse("24 dec 2026"), Amount = 468006.38 },
};

var lookup = initial.ToLookup(x => x.ID);

InfoList[] final =
    initial
        .Select(i =>
            new InfoList()
            {
                ID = i.ID,
                PurchaseDate = i.PurchaseDate,
                Amount = i.Amount,
                Quantity = lookup[i.ID].Count(),
            })
        .ToArray();

That gives:

final

If preserving the initial order isn't important then this works:

InfoList[] final =
(
    from i in initial
    group i by i.ID into gis
    from gi in gis
    select new InfoList()
    {
        ID = gi.ID,
        PurchaseDate = gi.PurchaseDate,
        Amount = gi.Amount,
        Quantity = gis.Count(),
    }
).ToArray();
  • Related