Search code examples
c#keyvaluepairsorteddictionary

How to compare values from one SortedDictionary to Add them to a new SortedDictionary?


I have 2 SortedDictionary "mainsd" && "valuesd". The conditions I'm trying to program says the following:

If the sum of Values of the 2 Keys above the MaxValue in "mainsd" is greater than or equal to the sum of Values of the 2 Keys below the MaxValue in "mainsd"

Then: Add the 2 KeyValuePairs above the MaxValue to "valuesd"

Else: Add the 2 KeyValuePairs below the MaxValue to "valuesd"

Keep Adding until valuesd.Values.Sum() reaches 50% of mainsd.Values.Sum()

In other words, compare the 2 values above and below the max, whichever is greater add to valuesd and expand until we reach 50% of mainsd total value.

"mainsd" contains the following
{
   Key , Value
500.10 , 500
500.09 , 1000
500.08 , 2000
500.07 , 3000
500.06 , 4500 --------> Step 6: 4500+5500 > 5000+4000 (Add 500.05 & 500.06 to "valuesd")
500.05 , 5500
500.04 , 6000 --------> Step 5: 6000+7000 > 5000+4000 (Add 500.03 & 500.04 to "valuesd")
500.03 , 7000
500.02 , 8500 --------> Step 2: 8500+9500 > 9000+8000 (Add 500.01&500.02 to "valuesd")
500.01 , 9500
500.00 , 10000 -------> Step 1: Max Value (Add to "valuesd") 
499.99 , 9000
499.98 , 8000 --------> Step 3: 9000+8000 > 7000+6000 (Add 499.99 & 499.98 to "valuesd")
499.97 , 7500
499.96 , 6500 --------> Step 4: 6500+7500 > 6000+7000 (Add 499.97 & 499.96 to "valuesd")
499.95 , 5000
499.94 , 4000--------> Step 7: 4000+3500 > 3000+2000 (Add 499.94 & 499.95 to "valuesd")
499.93 , 3500
499.92 , 2500
499.91 , 1500
499.90 , 550
}
Keep going until 50% is reached.

Here is what I got but it's not producing expected results.

mainsd = new SortedDictionary<double,int>(); 
valuesd = new SortedDictionary<double,int>();

if (!valuesd.ContainsKey(mainsd.Values.Max()))
{
 valuesd.Clear();
 valuesd.Add(mainsd.FirstOrDefault(x => x.Value == (mainsd.Values.Max()).Key),(mainsd.Values.Max()))
}

var vhi = valuesd.Keys.First();
var vlo = valuesd.Keys.Last();
double u1 = vhi+0.01;
double u2 = vhi+0.02;
double d1 = vlo+0.01;
double d2 = vlo+0.02;

if (mainsd.ContainsKey(u1) && mainsd.ContainsKey(u2))
{
 int up1 = mainsd[u1];
 int up2 = mainsd[u2];
}
if (mainsd.ContainsKey(d1) && mainsd.ContainsKey(d2))
{
 int dn1 = mainsd[d1];
 int dn2 = mainsd[d2];
}

if (valuesd.Values.Sum()/mainsd.Values.Sum() < 0.5)
{
 if (up1+up2>=dn1+dn2 && !valuesd.ContainsKey(u1) && !valuesd.ContainsKey(u2))
 {
  valuesd.Add(u1,up1);
  valuesd.Add(u2,up2);
 }
 else if (up1+up2<dn1+dn2 && !valuesd.ContainsKey(l1) && !valuesd.ContainsKey(l2))
 {
  valuesd.Add(d1,dn1);
  valuesd.Add(d2,dn2);
 }
}
Print("Hi="+valuesd.Keys.First()+"Lo="+valuesd.Keys.Last());

If the MAX Value was 500.

Output: Hi=500.01 Lo=499.99

Any help is greatly appreciated.


Solution

  • Here is an incomplete attempt using LINQ to obtain two sequences, one for enumerating forward (starting from the max item) and one for enumerating backward. After that point it is not easy to continue with LINQ, because the two sequences must be enumerated parallely in a complex way, so I went with a while loop.

    var mainsd = new SortedDictionary<double, int>()
    {
        {500.10, 500}, {500.09, 1000}, {500.08, 2000}, {500.07, 3000},
        {500.06, 4500}, {500.05, 5500}, {500.04, 6000}, {500.03, 7000},
        {500.02, 8500}, {500.01, 9500}, {500.00, 10000}, {499.99, 9000},
        {499.98, 8000}, {499.97, 7500}, {499.96, 6500}, {499.95, 5000},
        {499.94, 4000}, {499.93, 3500}, {499.92, 2500}, {499.91, 1500},
        {499.90, 550},
    };
    var maxValue = mainsd.Max(e => e.Value);
    var maxItemKey = mainsd.First(e => e.Value == maxValue).Key;
    var forward = mainsd.SkipWhile(e => e.Key <= maxItemKey).ToArray();
    var backward = mainsd.TakeWhile(e => e.Key < maxItemKey).Reverse().ToArray();
    int i1 = 0;
    int i2 = 0;
    while (true)
    {
        var sum1 = i1 < forward.Length - 1 ? forward[i1].Value + forward[i1 + 1].Value : 0;
        var sum2 = i2 < backward.Length - 1 ? backward[i2].Value + backward[i2 + 1].Value : 0;
        if (sum1 == 0 && sum2 == 0) break;
        if (sum1 >= sum2)
        {
            Console.WriteLine($"Forward:  {sum1}, Keys: {forward[i1].Key}, {forward[i1 + 1].Key}");
            i1 += 2;
        }
        else
        {
            Console.WriteLine($"Backward: {sum2}, Keys: {backward[i2 + 1].Key}, {backward[i2].Key}");
            i2 += 2;
        }
    }
    

    Output:

    Forward:  18000, Keys: 500,01, 500,02
    Backward: 17000, Keys: 499,98, 499,99
    Backward: 14000, Keys: 499,96, 499,97
    Forward:  13000, Keys: 500,03, 500,04
    Forward:  10000, Keys: 500,05, 500,06
    Backward: 9000, Keys: 499,94, 499,95
    Backward: 6000, Keys: 499,92, 499,93
    Forward:  5000, Keys: 500,07, 500,08
    Backward: 2050, Keys: 499,9, 499,91
    Forward:  1500, Keys: 500,09, 500,1
    

    Update: Here is what is missing to complete the program. Before entering the while loop we create the valuesd dictionary:

    var valuesd = new SortedDictionary<double, int>();
    

    Inside the while loop there are two cases. If sum1 >= sum2 we add two entries from the forward list:

    valuesd.Add(forward[i1].Key, forward[i1].Value);
    valuesd.Add(forward[i1 + 1].Key, forward[i1 + 1].Value);
    

    Otherwise (else) we add two entries from the backward list:

    valuesd.Add(backward[i2].Key, backward[i2].Value);
    valuesd.Add(backward[i2 + 1].Key, backward[i2 + 1].Value);
    

    At the end of the while loop we check if we have reached the goal of 50%. If we do, it is time to exit the loop by calling break.

    if (valuesd.Values.Sum() >= mainsd.Values.Sum() * 50 / 100) break;
    

    After exiting the loop, the valuesd dictionary is filled with the required entries.