2

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.

Community
  • 1
  • 1
Koda
  • 37
  • 5

1 Answers1

1

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.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • Thanks! Couple of questions, where would I put the condition to stop adding forward and backward when 50% is reached? Also, How would I add the keys you produced in your output into "valuesd"? – Koda Apr 20 '19 at 23:13
  • You can create a variable outside the while loop that will hold the current sum, and inside the loop you will increment this variable with either the sum1 or the sum2. Then (still inside the loop) you can check if the current sum has become larger than half of the total. The total should be precalculated before entering the loop, probably using LINQ (method [Sum](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sum)). The valuesd can be populated with the method [Add](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2.add). – Theodor Zoulias Apr 20 '19 at 23:45
  • Thank you very much Mr. Zoulias – Koda Apr 21 '19 at 19:44
  • Mr. Zoulias, I've been working on this code since April and I got everything down except for the check if current sum is larger than half the total... Everything I try leads to a system crash... Could you show me what you mean by your Apr 20th comment? Much appreciated – Koda Jun 30 '19 at 01:25
  • Thank you so much! It's working perfectly now. Appreciate all your help. – Koda Jun 30 '19 at 04:05
  • I just experienced an error message saying index was outside the bounds of the array... when I removed [i1+1] and [i2+1] and reduced the increment from 2 to 1 inside the loop, it worked again but is not giving the expected results... Do you have any recommendations to fix this error? – Koda Jul 01 '19 at 02:27
  • My answer solves the specific problem you described in your question. If you now have a different problem, I think you should probably ask a new question. – Theodor Zoulias Jul 01 '19 at 08:30