What I am looking for isn't a problem solution but maybe a better c# logic.
Basically, I have a got a value which is a sum of any of those values {1, 2, 4}.
Then I will do some actions depends on those values in descending order.
Check the code below:
byte value = 7;//could be 1,2,3,4,5,6,7 which is the summation of any of those 3 numbers {1, 2, 4}
bool case1 = false, case2 = false, case3 = false;
if (value >= 4)
{
case1 = true;
value -= 4;
}
if (value >= 3)
{
case2 = true;
value -= 3;
}
if (value >= 1)
{
case3 = true;
value -= 1;
}
if (case3)
{
//do some action
}
if (case2)
{
//do some action
}
if (case1)
{
//do some action
}
Note that: Any of the numbers is not repeated in the summation.
That's what I have written in c#, But that doesn't make me feel good about the code logic in 2k17.
Hope someone has a better logic with any mathematical operation!
Thanks in advance.
(Edited again... code sample)
Instead of using an int, could you use an enum?
public enum MyEnum
{
Nothing = 0,
One = 1,
Two = 2,
Four = 4,
Seven = 7
}
MyEnum seven = MyEnum.Seven;
if( (seven & MyEnum.Four) == MyEnum.Four)
{
Console.WriteLine("Four");
}
if((seven & MyEnum.Two) == MyEnum.Two)
{
Console.WriteLine("Two");
}
if((seven & MyEnum.One) == MyEnum.One)
{
Console.WriteLine("One");
}
previous tip: bit masks, easy to understand examples here http://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
I think your original code is wrong and the second if should be if (value >= 2) instead of if (value >= 3), but that's beside the point. If I understand what you want to achieve then this console application should be of help:
class Program
{
static void Main(string[] args)
{
int value = 7;
int copy = value; // only needed for the Console.WriteLine below
var allComponents = new[] { 4, 2, 1 };
var sumParts = new List<int>();
int i = 0;
while (i < allComponents.Length)
{
if (value >= allComponents[i])
{
value -= allComponents[i];
sumParts.Add(allComponents[i]); // or do some action whatever you need
}
i++;
}
Console.WriteLine("Value {0} is the sum of {1}", copy, string.Join(" + ", sumParts));
}
}
Outputs for the possible values (7, 6, 5, 4, 3, 2, 1):
Value 7 is the sum of 4 + 2 + 1
Value 6 is the sum of 4 + 2
Value 5 is the sum of 4 + 1
Value 4 is the sum of 4
Value 3 is the sum of 2 + 1
Value 2 is the sum of 2
Value 1 is the sum of 1
It's looping through all the components from largest to smallest (4, 2, 1), checking if the current one is larger or equal to the value, if yes, then decrements value by the current component and adds the current component to the sumParts list.
If you can invoke your logic from inside the if in the loop, then you don't even need the sumParts, just do whatever you need there.
This solution is basically the same as yours, but rolled into a loop instead of statements after each other.
Related
I have 2 arrays one of the types of numbers that will be used and the 2nd array is how many times that number can be used. I have a letter that determines what kind of method will be used I need to figure out how many times I can use a certain number from an array to determine a letter+number The ‘number’ is what I have to make with all the available numbers I can use. If the number cannot be made I would like to just say number cant be made or anything but allow the program to move on.
Here is what I have
int[] picksToUse = { 100, 50, 20, 10, 5, 1 };
int[] timesToUse = { 10, 10, 10, 10, 10, 10 };
string choice = Console.ReadLine();
string input = "";
if(choice.Length > 2)
{
input = choice.Substring(choice.IndexOf("$") + 1);
}
if(...){
}
else if (choice.Equals("D"))
{
int amt = Convert.ToInt32(input);
// code here to determine if number can be made with above choices
Dispense(amt, timesToUse);
}
Assuming picksToUse and timesToUse are exactly the same as you declared them, here's a way to know if you have enough of everything in stock to "pay up". It's a boolean function, which uses recursion. You would call it with the amount needed as parameter, and it would tell you right there if you have enough of everything.
Private Function HasCashInStock(amount As Integer, Optional index As Integer = 0) As Boolean
Dim billsNeeded As Integer = amount \ picksToUse(index)
If billsNeeded > timesToUse(index) Then
Return False
End If
amount -= picksToUse(index) * billsNeeded
If amount = 0 Then
Return True
End If
Return HasCashInStock(amount, index + 1)
End Function
The \ is an integer division operator (in VB.NET, at least - I'm shamelessly letting you translate this code). If you're not familiar with the integer division operator, well, when you use it with integer it gets rid of the floating numbers.
3 / 2 is not valid on integers, because it would yield 1.5.
3 \ 2 is valid on integers, and will yield 1.
That's all there is to it, really. Oh yeah, and recursion. I like recursion, but others will tell you to avoid it as much as you can. What can I say, I think that a nice recursive function has elegance.
You can also totally copy this function another time, modify it and use it to subtracts from your timesToUse() array once you know for sure that there's enough of everything to pay up.
If HasCashInStock(HereIsTheAmountAsInteger) Then
GivesTheMoney(HereIsTheAmountAsInteger)
End If
Having two functions is not the leanest code but it would be more readable. Have fun!
This is what I used to finish my project.
public static bool Validate(int amount, int[] total, int[] needed)
{
int[] billCount = total;
int[] cash = { 100, 50, 20, 10, 5, 1 };
int total = amount;
bool isValid = true;
for (int i = 0; i < total.Length; i++)
{
if(total >= cash[i])
{
billCount[i] = billCount[i] - needed[i];
}
if(billCount[i] < 0)
{
isValid = false;
break;
}
}
return isValid;
}
I got some working code. I did it with a class. I remember when I couldn't see what good classes were. Now I can't brush my teeth without a class. :-)
I force myself to do these problems to gain a little experience in C#. Now I have 3 things I like about C#.
class ATM
{
public int Denomination { get; set; }
public int Inventory { get; set; }
public ATM(int denom, int inven)
{
Denomination = denom;
Inventory = inven;
}
}
List<int> Bills = new List<int>();
List<ATM> ATMs = new List<ATM>();
private void OP2()
{
int[] picksToUse = { 100, 50, 20, 10, 5, 1 };
foreach (int d in picksToUse )
{
ATM atm = new ATM(d, 10);
ATMs.Add(atm);
}
//string sAmtRequested = Console.ReadLine();
string sAmtRequested = textBox1.Text;
if (int.TryParse(sAmtRequested, out int AmtRequested))
{
int RunningBalance = AmtRequested;
do
{
ATM BillReturn = GetBill(RunningBalance);
if (BillReturn is null)
{
MessageBox.Show("Cannot complete transaction");
return;
}
RunningBalance -= BillReturn.Denomination;
} while (RunningBalance > 0);
}
else
{
MessageBox.Show("Non-numeric request.");
return;
}
foreach (int bill in Bills)
Debug.Print(bill.ToString());
Debug.Print("Remaining Inventory");
foreach (ATM atm in ATMs)
Debug.Print($"For Denomination {atm.Denomination} there are {atm.Inventory} bills remaining");
}
private ATM GetBill(int RequestBalance)
{
var FilteredATMs = from atm in ATMs
where atm.Inventory > 0
orderby atm.Denomination descending
select atm;
foreach (ATM bill in FilteredATMs)
{
if (RequestBalance >= bill.Denomination )
{
bill.Inventory -= 1;
Bills.Add(bill.Denomination);
return bill;
}
}
return null;
}
I want to pass a number and have the next whole number returned,
I've tried Math.Ceiling(3) , but it returns 3.
Desired output :
double val = 9.1 => 10
double val = 3 => 4
Thanks
There are two ways I would suggest doing this:
Using Math.Floor():
return Math.Floor(input + 1);
Using casting (to lose precision)
return (int)input + 1;
Fiddle here
Using just the floor or ceiling wont give you the next whole number in every case.
For eg:- If you input negative numbers. Better way is to create a function that does that.
public class Test{
public int NextWholeNumber(double n)
{
if(n < 0)
return 0;
else
return Convert.ToInt32(Math.Floor(n)+1);
}
// Main method
static public void Main()
{
Test o = new Test();
Console.WriteLine(o.NextWholeNumber(1.254));
}
}
Usually when you refer to whole number it is positive integers only. But if you require negative integers as well then you can try this, the code will return 3.0 => 4, -1.0 => 0, -1.1 => -1
double doubleValue = double.Parse(Console.ReadLine());
int wholeNumber = 0;
if ((doubleValue - Math.Floor(doubleValue) > 0))
{
wholeNumber = int.Parse(Math.Ceiling(doubleValue).ToString());
}
else
{
wholeNumber = int.Parse((doubleValue + 1).ToString());
}
I am trying to find the sum of a list in a recursive algorithm
i am learning recursive algorithm, i know i can do it in another way but i am learning
this is my code (pretty simple)
class SumList
{
public SumList(int[] list ) {
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
sum(listInteger);
}
private double sum(List<int> list) {
if (list.Count == 1)
{
return list[0];
}
if(list.Count ==2)
{
Console.Write(printList(list));
Console.WriteLine((list[0] + list[1]));
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count -1);
double s = last + sum(list);
Console.Write(printList(backupList));
Console.WriteLine(s);
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result +="+ ";
}
else
{
result+= " = ";
}
}
return result;
}
}
and this call it like this:
int []listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
new SumList(listInt);
Console.ReadLine();
my problem is that the result is:
i would like to have the result but like this:
4 + 5 + 6 + 7 = ...
4 + 5 + 6 = ...
so the results should be printed backwards
again i do know that there are millinos of way to find the sum of a list, but am trying to learn recursive algorithsm
As you probably know, a recursive function is a function that calls itself. This means that in order to solve a problem recursively, we must divide the problem in to steps such that the procedure will not change between steps, but the input to the function will change. Moreover, if our recursive function is ever to correctly terminate, the problem must get "smaller" with each step we take. This step represents one unit of recursion. Also, unlike with "normal" iteration, we do not know ahead of time when we are going to reach the end of the problem. Therefore, we need a mechanism to determine when we have reached the end of the problem and should stop recursing. This is known as the base case.
Let's try your example of finding the sum of a list.
The first thing we must do is come up with a unit of recursion (one abstract step that we can repeat over and over until we find the solution).
We know we have an input type of List<int>
In this case we can notice (psuedocode here) that sum(list) == list[0] + sum(restOfList). Notice that now we have a definite value (list[0]) and an object of type List<int> (namely restOfList).
So, now we have a neat, repeatable procedure.
//Idk what language you are using, or if it matters, but I am writing this in java
public int sum(List<Integer> list) {
//still need a base case
return list.get(0) + sum(list.subList(1, list.size()));
}
Now we only need to determine the base case. So we need to determine when we will have gone through all the elements of the list.
For this let's run through a few steps to see what will happen. Let's start with the following list: {1, 2, 3, 4}
sum({1, 2, 3, 4})
-> 1 + sum({2, 3, 4})
-> 2 + sum({3, 4})
-> 3 + sum({4})
-> 4 + oops!!!
Clearly, we cannot get the sublist beginning at index 1 from a list of size 1. This gives us the answer for what our base case should be.
public int sum(List<Integer> list) {
printList(list);
//base case
if (list.size() == 1)
return list.get(0); //recall that this is the entire list
//otherwise, continue to next step.
return list.get(0) + sum(list.subList(1, list.size()));
}
The addition works because the return statement of the first step is dependent on the return statement of the second step and so on. This is also why the steps will print in reverse order.
Just for clarity, let's trace through it one final time.
sum({1, 2, 3, 4}) //sum({1, 2, 3, 4}) is called from main()
-> 1 + sum({2, 3, 4}) //sum({2, 3, 4}) is called from sum({1, 2, 3, 4})
-> 2 + sum({3, 4}) //sum({3, 4}) is called from sum({2, 3, 4})
-> 3 + sum({4}) //sum({4}) is called from sum({3, 4})
<- 4 //sum({4}) returns 4 to sum({3, 4})
3 + 4
<- 7 //sum({3, 4}) returns 7 to sum({2, 3, 4})
2 + 7
<- 9 //sum({2, 3, 4}) returns 9 to sum({1, 2, 3, 4})
1 + 9
<- 10 //sum({1, 2, 3, 4}) returns 10
I hope this helped make things a little bit clearer.
Or try this
public static int Sum(List<int> listOfInt)
{
if (listOfInt.Count == 1)
{
return Convert.ToInt32(listOfInt[0]);
}
else
{
return Convert.ToInt32(listOfInt[0]) + Sum(listOfInt.Skip(1).ToList());
}
}
Well, this is not how I would do it, and it definitely has a number of oddities. But if I try to preserve the spirit behind your design, then I think a good way to accomplish this is by buffering the output in a StringBuilder, and using its Insert(0, str) method to place the lines in the right place.
public SumList(int[] list)
{
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
StringBuilder output = new StringBuilder();
sum(listInteger, output);
Console.WriteLine(output.ToString());
}
private double sum(List<int> list, StringBuilder output)
{
if (list.Count == 1)
{
return list[0];
}
if (list.Count == 2)
{
output.Append(printList(list));
output.Append((list[0] + list[1])).Append(Environment.NewLine);
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count - 1);
double s = last + sum(list, output);
output.Insert(0, Environment.NewLine);
output.Insert(0, s);
output.Insert(0, printList(backupList));
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result += " + ";
}
else
{
result += " = ";
}
}
return result;
}
Your code works by calculating the sums of all of the lists (and decreasing the lists as it goes) and then printing them going backwards, which explains why the lists you see are increasing in size. The way to fix this is by fixing your recursion. In order to have them printing in decreasing order, you want your recursion to go in increasing order. So, calculate sum(List.subList(1)), then sum(List.subList(2)), and so on...
An alternative quick fix is to save the output as a strings in an array and just print the array backwards.
One possible solution is
List<int> listInteger = new List<int> ();
public SumList (int[] list)
{
for (int i = 0; i < list.Length; i++)
listInteger.Add (list [i]);
listInteger.Reverse();
}
private void sumR (List<int> list, int index)
{
int sigma = 0;
if (list.Count - 1 == index) {
return;// sigma + list [index];
} else {
for (int i = list.Count-1; i>=index; i--) {
sigma += list [i];
if (i == list.Count - 1)
Console.Write ("{0} ", list [i]);
else
Console.Write ("+ {0} ", list [i]);
}
Console.WriteLine ("= {0}", sigma);
sumR (list, index + 1);
}
}
public void doSum(){
sumR(listInteger, 0);
}
There is no need for other methods, though you can call sumR from constructor if you like. Test is
int [] listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
SumList sl = new SumList (listInt);
sl.doSum();
Console.ReadLine ();
Output is:
4 + 5 + 6 + 7 + 9 + 10 = 41
4 + 5 + 6 + 7 + 9 = 31
4 + 5 + 6 + 7 = 22
4 + 5 + 6 = 15
4 + 5 = 9
The recursive function:
public static void PrintSum(int[] list)
{
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
// Print the result of list AFTER shorter list is done
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
}
public static void PrintSumReverse(int[] list)
{
// Print the result of list
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
}
Usage:
var listInt = new int[] { 4, 5, 6, 7, 9, 10 };
PrintSum(listInt);
/* Result:
4+ 5 = 9
4+ 5+ 6 = 15
4+ 5+ 6+ 7 = 22
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7+ 9+ 10 = 41
*/
PrintSumReverse(listInt);
/* Result
4+ 5+ 6+ 7+ 9+ 10 = 41
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7 = 22
4+ 5+ 6 = 15
4+ 5 = 9
*/
So there's this blog that gives Five programming problems every Software Engineer should be able to solve in less than 1 hour and I'm just revisiting some of the concepts.
The first question reads
Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop, and recursion.
Obviously the for- and while-loops are easy, but i started out with
int[] l = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
Is it at all possible to pop an item off the list and then pass the shortened list every time?
An attempt I saw in python:
numbers = [1,2,3,4,5,6,7,8,9]
def recurse_count(lst):
if len(lst) == 1:
return lst[0]
else:
i = len(lst) - 1
subtotal = lst[i] + lst[i - 1]
lst.pop() #into the void with you
lst[-1] = subtotal
return recurse_count(lst)
Would it be possible with a int[] in c# ?
A very elegant solution would be:
static public int sumThisUp(IEnumerable<int> list)
{
return list.FirstOrDefault() + (list.Any() ? sumThisUp(list.Skip(1)) : 0);
}
Yes. I do belive the List-class has a simple removeAt(int)-method. A recursive method would look like this:
public int sumThisUp(List<int> list) {
int result = list[0];
list.removeAt(0);
return (list.length > 0) ? result + sumThisUp(list) : result;
}
Alternatively if you dont wanna edit the orginal list this would do:
public int sumThisUp2(List<int> list, int index = 0) {
int result = list[index++];
return (list.Count > index) ? result + sumThisUp2(list, index) : result;
}
Yes, it is possible in C#.
But I want to introduce some trick first: instead of modifying the source list we can just pass the start index. It will be much faster:
private static int Sum(int[] array, int startIndex)
{
if (startIndex >= array.Length)
{
return 0;
}
return array[startIndex] + Sum(array, startIndex + 1);
}
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3, 4 };
int result = Sum(array, 0);
Console.WriteLine(result);
}
This should do it:
public int Sum(int[] numbers, int startAt = 0)
{
if (startAt == numbers.Length)
return 0;
return numbers[startAt] + Sum(numbers, startAt + 1);
}
I have to get the sum of a list of doubles. If the sum is > 100, I have to decrement from the highest number until it's = 100. If the sum is < 100, I have to increment the lowest number until it's = 100. I can do this by looping though the list, assigning the values to placeholder variables and testing which is higher or lower but I'm wondering if any gurus out there could suggest a super cool & efficient way to do this? The code below basically outlines what I'm trying to achieve:
var splitValues = new List<double?>();
splitValues.Add(Math.Round(assetSplit.EquityTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.PropertyTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.FixedInterestTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.CashTypeSplit() ?? 0));
var listSum = splitValues.Sum(split => split.Value);
if (listSum != 100)
{
if (listSum > 100)
{
// how to get highest value and decrement by 1 until listSum == 100
// then reassign back into the splitValues list?
var highest = // ??
}
else
{
// how to get lowest where value is > 0, and increment by 1 until listSum == 100
// then reassign back into the splitValues list?
var lowest = // ??
}
}
update: the list has to remain in the same order as the items are added.
I think the most efficient thing is probably to not use the List.Sum() method, and do one loop that calculates the sum, lowest, and highest. It's also easy to write, debug, read, and maintain, which I would say qualifies as super-cool.
Update: Gah, I didn't notice that you seem to only have 4 elements in the list. The answer here is for the general case, and will be overkill for a 4-element problem. Go with looping.
Well, personally I would use a Heap data structure, where each element is the value of each element + its position in the original list.
You need to hunt down a good Heap implementation for C# though. You can use mine, but it is part of a larger class library so it might be a bit of a rubber ball to pull into your project. The code is here: My Mercurial Repository.
I'll be showing examples below on how my implementation would work.
If you don't know how a heap works, it is basically a data structure that looks a bit like an array, but also a bit like a tree, where the nodes of the tree is stored in the array. There's a bit of code involved that "intelligently" moves items around. The beauty of it is that it is super easy to get the highest or lowest item (that is, one of them, not both from the same heap), since it will always be the first element in the array.
So what I would do is this:
Create a heap containing value+position for all elements, sorted so that the highest value is the first one
Create a heap containing value+position for all elements, sorted so that the lowest value is the first one
Then, if the sum < 0, grab the first element of the heap (value + position), increase the value in the original list by 1, then replace the first element of the heap with (value+1),position. Replacing the first element of the heap has the effect of removing it, and then readding it, potentially moving it to a different position than the first one if it is no longer the highest/lowest value. For instance, let's say you have the following list:
list: 1, 2, 3
The heap now looks like this:
heap: (1, 0), (2, 1), (3, 2) <-- second value is position, 0-based
ie. you build it up like this:
position: 0, 1, 2
list: 1, 2, 3
| | +-------+
| | |
+-+ +--+ |
| | |
<-+> <-+> <-+>
heap: (1, 0), (2, 1), (3, 2)
Now, if the sum is too low, you grab the first element of the lo-heap, which is (1, 0), increase the value at position 0 in the original list by 1, then replace the first element of the heap (which is still (1, 0)) with a new element containing the new value, at the same position.
After the replace, the list and heap now looks like this:
list: 2, 2, 3
heap: (2, 0), (2, 1), (3, 1)
Let's say the sum is still to low, so you repeat. Now, when re-adding (3, 0) instead of (2, 0), it will be pushed a bit back into the heap, so it looks like this:
list: 3, 2, 3
heap: (2, 1), (3, 0), (3, 1)
Now, the 2-value is now the lowest one, and thus the first element of the heap. Note that these operations does not reorder the entire heap, only the portions necessary. As such, a heap is ideal for algorithms like this since they are cheap to keep sorted when doing modifications.
So let's see some code. I'm assuming you have an array of values like this:
int[] values = new int[] { ... };
Thus, with my heap implementation, the following would do what you want:
using System;
using System.Collections.Generic;
using System.Linq;
using LVK.DataStructures.Collections;
namespace SO3045604
{
class LowestComparer : IComparer<Tuple<int, int>>
{
public int Compare(Tuple<int, int> x, Tuple<int, int> y)
{
return x.Item1.CompareTo(y.Item1);
}
}
class HighestComparer : IComparer<Tuple<int, int>>
{
public int Compare(Tuple<int, int> x, Tuple<int, int> y)
{
return -x.Item1.CompareTo(y.Item1);
}
}
class Program
{
static void Main(string[] args)
{
int[] values = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var valuesWithPositions = values
.Select((value, index) => Tuple.Create(value, index));
var loHeap = new Heap<Tuple<int, int>>(
new LowestComparer(),
valuesWithPositions);
var hiHeap = new Heap<Tuple<int, int>>(
new HighestComparer(),
valuesWithPositions);
int sum = values.Aggregate((a, b) => a + b);
while (sum < 75)
{
var lowest = loHeap[0];
values[lowest.Item2]++;
loHeap.ReplaceAt(0,
Tuple.Create(lowest.Item1 + 1, lowest.Item2));
sum++;
}
while (sum > 55)
{
var highest = hiHeap[0];
values[highest.Item2]--;
hiHeap.ReplaceAt(0,
Tuple.Create(highest.Item1 - 1, highest.Item2));
sum--;
}
// at this point, the sum of the values in the array is now 55
// and the items have been modified as per your algorithm
}
}
}
The most efficient way is to write a plain and simple loop that does the work, that will give the least amount of overhead. You have to look at all values in the list to find the largest or smallest, so there is no shortcuts.
I think that the most efficient would be to make an index sort, i.e. create an array of indexes that you sort by the values that they point to. When you start to increment or decrement the values, you may need more than just the smallest or largest number.
If I read that code correctly your List<> is only going to have exactly 4 members, right?
If so, looping is not required or recommended.
Just store your data in 4 vars and puzzle it out with if/then
I'd do it something like this:
var splitValues = new List<double?>();
splitValues.Add(Math.Round(assetSplit.EquityTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.PropertyTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.FixedInterestTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.CashTypeSplit() ?? 0));
var listSum = splitValues.Sum(split => split.Value);
while (listSum != 100)
{
var value = listSum > 100 ? splitValues.Max() : splitValues.Min();
var idx = splitValues.IndexOf(value);
splitValues.RemoveAt(idx);
splitValues.Insert(idx, value + (listSum > 100 ? -1 : 1));
listSum = splitValues.Sum(split => split.Value);
}
Note: This solution would work for any number of elements in the list.
Not sure if I understood your question... How about this?
const double MIN_VALUE = 0.01;
var values = new List<double>();
var rand = new Random();
for (int i = 0; i < 100; i++)
{
values.Add(rand.Next(0, 100) / 10);
}
double sum = 0, min = 0, max = 0;
for (int i = 0; i < values.Count; i++)
{
var value = values[i];
sum += value;
min = Math.Min(value, min);
max = Math.Max(value, max);
}
if (min == 0) min = MIN_VALUE;
if (max == 0) max = MIN_VALUE;
while (Math.Abs(sum - 100) > MIN_VALUE)
{
if (sum > 100)
sum -= max;
if (sum < 100)
sum += min;
}
Here's an implementation using Linq's Aggregate method (assuming list is a list or array of doubles, or anything that implements IList<double>) :
var stats = list.Aggregate(
StatsAggregate.Default,
(a, v) => a.ProcessValue(v));
if (stats.Sum > 100.0)
{
list[stats.MaxIndex] -= (stats.Sum - 100.0);
}
else if (stats.Sum < 100.0)
{
list[stats.MinIndex] += (100.0 - stats.Sum);
}
...
struct StatsAggregate
{
public static StatsAggregate Default
{
get
{
return new StatsAggregate
{
Sum = 0,
Min = double.MaxValue,
MinIndex = -1,
Max = double.MinValue,
MaxIndex = -1
};
}
}
private int currentIndex;
public double Sum { get; private set; }
public double Min { get; private set; }
public double Max { get; private set; }
public int MinIndex { get; private set; }
public int MaxIndex { get; private set; }
public StatsAggregate ProcessValue(double value)
{
return new StatsAggregate
{
Sum = this.Sum + value,
Max = Math.Max(this.Max, value),
MaxIndex = value > this.Max ? currentIndex : MaxIndex,
Min = Math.Min(this.Min, value),
MinIndex = value < this.Max ? currentIndex : MinIndex,
currentIndex = currentIndex + 1
};
}
}
The advantage of this technique is that it iterates the list only once, and the code is clearer than with a foreach loop (IMHO...)
It appears as though I misunderstood the question at first. Apparently the goal is not to find the highest/lowest and add +/-1 to that element until the sum is 100; the goal is to find the new highest/lowest every time you add +/-1.
Here's another answer, based on Sani's:
var splitValues = new List<double?>();
splitValues.Add(Math.Round(assetSplit.EquityTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.PropertyTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.FixedInterestTypeSplit() ?? 0));
splitValues.Add(Math.Round(assetSplit.CashTypeSplit() ?? 0));
var listSum = splitValues.Sum();
while (listSum != 100)
{
int increment = listSum > 100 ? -1 : 1;
var value = listSum > 100 ? splitValues.Max() : splitValues.Min();
splivValue[splitValues.IndexOf(value)] += increment;
listSum += increment;
}
To get highest... in a very simple way:
// For type safety
List<double> list = new List<double>()
{ 1.2, 4.3, 7.8, 4.4, 9.3, 10.2, 55.6, 442.45, 21.32, 43.21 };
d.Sort();
list.Sort();
Console.WriteLine(d[d.Count - 1].ToString());
Console.WriteLine(list[list.Count - 1]);