Again another one of those moments when my brain has completely failed me.
I am trying to add(Addition) two values(decimals) from two separate Lists. In all honesty i think I'm running into value type issues but any clarification welcome.
public List<decimal> getTotalSellingPrice(int costSheetID)
{
List<decimal> totalSellingPrice = new List<decimal>();
decimal bothMarkupAndToms = 0;
foreach (var i in getMarkupPrice(costSheetID))
{
foreach (var m in getToms(costSheetID))
{
bothMarkupAndToms = i + m;
}
totalSellingPrice.Add(Math.Round(bothMarkupAndToms));
}
return totalSellingPrice;
}
As you can see for each item in each collection i want to add to another value within the nested collection.
So on each pass it should "i + m" then add to the final list ready for the UI.
Any help would be extremely appreciated!
This will give you the sum of each value from getTotalSellingPrice() with it's corresponding value from getToms(). If both the lists have 4 values each this will give you 4 values in the resulting list. What you were doing was more like permutation. This is proper addition of two lists.
public List<decimal> getTotalSellingPrice(int costSheetID)
{
List<decimal> totalSellingPrice = new List<decimal>();
List<object> toms = getToms(costSheetID);
int j = 0,
tomsCount = toms.Count;
foreach (var i in getMarkupPrice(costSheetID))
{
if(j >= tomsCount )
break;
totalSellingPrice.Add(Math.Round(i + Convert.ToDecimal(toms[j])));
j++;
}
return totalSellingPrice;
}
For each value in getMarkupPrice(), the above code is adding the corresponding value from toms (based on the index j it uses to track the current value in toms) and adding the result in the totalSellingPrice list. The additional if block inside the foreach checks if the toms is out of values. If yes, the break; statement just exits the execution of that foreach loop.
The problem is with your 2 foreach loops. You're creating i * m values with your code instead of matching i to m and then adding them. For each i you get 4 m so 4 * 4 will give you 16 values.
If you want to put an item (i+m) into the list, try the following:
public List<decimal> getTotalSellingPrice(int costSheetID)
{
List<decimal> totalSellingPrice = new List<decimal>();
foreach (var i in getMarkupPrice(costSheetID))
{
foreach (var m in getToms(costSheetID))
{
totalSellingPrice.Add(Math.Round(i + m));
}
}
return totalSellingPrice;
}
And if you want to out an item for each i (sum of all m for that i) try the following:
public List<decimal> getTotalSellingPrice(int costSheetID)
{
List<decimal> totalSellingPrice = new List<decimal>();
decimal bothMarkupAndToms = 0;
foreach (var i in getMarkupPrice(costSheetID))
{
bothMarkupAndToms = i;
foreach (var m in getToms(costSheetID))
{
bothMarkupAndToms += m;
}
totalSellingPrice.Add(Math.Round(bothMarkupAndToms));
}
return totalSellingPrice;
}
I hope that help
Edit:
I think you are try to add corresponding elements from those two lists, for example first element from markup prices with first element from toms and so on. Based on that scenario you want something like bellow:
public List<decimal> getTotalSellingPrice(int costSheetID)
{
List<decimal> totalSellingPrice = new List<decimal>();
decimal bothMarkupAndToms = 0;
List<decimal> markupPriceList = getMarkupPrice(costSheetID);
List<decimal> tomsList = getToms(costSheetID);
for(int i = 0 ; i < tomsList.size() ; i++)
{
totalSellingPrice.Add(Math.Round(markupPriceList[i] + tomsList[i]));
}
return totalSellingPrice;
}
Related
I would like to show the LinkedList data into three separate columns with List1, List2, and List3 as the column heading. I am unable to align the LinkedList data under these headings.
void LoopThruLinkedList(LinkedList<string> strList)
{
foreach(string str in strList)
{
Console.WriteLine(string.Format($"{str, -20}"));
}
//Console.WriteLine();
}
// Creating a linkedlist
// Using LinkedList class
LinkedList<string> my_list = new LinkedList<string>();
// Adding elements in the LinkedList
// Using AddLast() method
my_list.AddLast("Zoya");
my_list.AddLast("Shilpa");
my_list.AddLast("Rohit");
my_list.AddLast("Rohan");
my_list.AddLast("Juhi");
my_list.AddLast("Zoya");
my_list.AddLast("Rohit");
string List1 = "List One Students: ";
string List2 = "List Two Students: ";
string List3 = "List Three Students: ";
Console.WriteLine($"{List1, -20}{List2, -20}{List3, -20}");
// Accessing the elements of LinkedList using the foreach loop
LoopThruLinkedList(my_list);
LoopThruLinkedList(my_list);
LoopThruLinkedList(my_list);
There are a lot of issues here
Why do you need linkedList? they have no indexers and makes any solution inefficent
Why are all the lists the same, however maybe this is just an example.
You need to flatten this somehow to write it to the console sequentially
However this might point you in the right direction
void LoopThruLinkedList(params LinkedList<string>[] strLists)
{
var max = strLists.Max(x => x.Count());
for (int i = 0; i < max; i++)
{
foreach (var item in strLists)
Console.Write($"{(item.Count > i ? item.ElementAt(i) : ""),-20}");
Console.WriteLine();
}
}
// Creating a linkedlist
// Using LinkedList class
LinkedList<string> my_list = new LinkedList<string>();
// Adding elements in the LinkedList
// Using AddLast() method
my_list.AddLast("Zoya");
my_list.AddLast("Shilpa");
my_list.AddLast("Rohit");
my_list.AddLast("Rohan");
my_list.AddLast("Juhi");
my_list.AddLast("Zoya");
my_list.AddLast("Rohit");
string List1 = "List One Students: ";
string List2 = "List Two Students: ";
string List3 = "List Three Students: ";
Console.WriteLine($"{List1,-20}{List2,-20}{List3,-20}");
// Accessing the elements of LinkedList using the foreach loop
LoopThruLinkedList(my_list, my_list, my_list);
Or another variation using enumeration in a pivot style operation with GroupBy
void LoopThruLinkedList(params LinkedList<string>[] strLists)
{
var results = strLists
.SelectMany(inner => inner.Select((item, index) => new { item, index }))
.GroupBy(i => i.index, i => i.item)
.Select(g => g.ToList());
foreach (var list in results)
{
foreach (var item in list)
Console.Write($"{item,-20}");
Console.WriteLine();
}
}
Here is a variation that uses only enumerators and is therefore more efficient than accessing elements by index:
void PrintLists(LinkedList<string>[] lists, string[] captions)
{
//Find the necessary column widths
var columnWidths = new int[lists.Length];
for(int i = 0; i < lists.Length; ++i)
{
columnWidths[i] = captions[i].Length;
foreach (var s in lists[i])
columnWidths[i] = Math.Max(columnWidths[i], s.Length);
columnWidths[i] += 2; //spacing
}
//Print the headings
for(int i = 0; i < lists.Length; ++i)
Console.Write(captions[i].PadRight(columnWidths[i]));
Console.WriteLine();
//Initialize iterators
var iterators = new LinkedList<string>.Enumerator[lists.Length];
var iteratorsValid = new bool[lists.Length];
for (int i = 0; i < lists.Length; ++i)
{
iterators[i] = lists[i].GetEnumerator();
iteratorsValid[i] = iterators[i].MoveNext();
}
//Print the rest of the table
while (iteratorsValid.Any(b => b))
{
for (int i = 0; i < lists.Length; ++i)
{
if (iteratorsValid[i])
{
var item = iterators[i].Current;
Console.Write(item.PadRight(columnWidths[i]));
iteratorsValid[i] = iterators[i].MoveNext();
}
else
Console.Write(new String(' ', columnWidths[i]));
}
Console.WriteLine();
}
}
Which you call like
PrintLists( new [] { my_list, my_list, my_list},
new [] { "List One Students: ", "List Two Students: ", "List Three Students: " });
I have a List<List<string>> with three nested lists. Now I need to check if List[1] equals a certain string and if so, check if the value at this index in List[2] has another certain string. If both conditions return true, then I need to get that certain index and get the item of List[0].
For example:
var list = Titles[0];
var list2 = Titles[1];
var list3 = Titles[2];
foreach (var item in list2)
{
if (item.Contains("Dt."))
{
int idx = list2.IndexOf(item);
var value = list3.ElementAt(idx);
if (value.Contains("25.04.2017"))
{
var newList = list.ElementAt(idx);
}
}
}
This approach doesn't seem very efficient in regards to performance, especially if the nested list contains ~9000 items.
I tried to get the result via lambda expressions first, but I'm not sure if this is the right approach either.
What would be the best or most efficient solution?
Eliminate ElementAt with direct access to index. I believe ElementAt iterates over List in order to get i'th element
Eliminate usage of IndexOf with index provided by for loop I believe IndexOf iterates over List in order to find matching element.
var list = Titles[0];
var list2 = Titles[1];
var list3 = Titles[2];
for (int i = 0 ; i < list2.Count; ++ i)
{
var item = list2[i];
if (item.Contains("Dt."))
{
var value = list3[i];
if (value.Contains("25.04.2017"))
{
var newList = list[i];
}
}
}
Note if size of list2 is greater than size of list or list3 then you potentially get IndexOutOfRangeException
Lambda equivalent for your code:
if(list2.Any(item => item.Contains("Dt.")))
{
int idx = list2.IndexOf("Dt.");
if(list3.ElementAt(idx).Contains("25.04.2017"))
{
var newList = list.ElementAt(idx);
}
}
for (int i = 0; i < list2.Count; ++i)
{
var item = list2[i];
if (item.Contains("Dt."))
{
var value = list3[i];
if (value.Contains("25.04.2017"))
{
var newList = list[i];
break; // Break the loop :-)
}
}
}
I want to add Array items inside forach loop.
My RegionalEarn array comes like this,
[0]Region1=25
[1]Region2=50
I need final RModel.TAX Should be 75(25+50) But in my case it comes like 2550
My Code
string[] RegionalEarn = tickets["EARN"].ToString().Split(',');
foreach (var item in RegionalEarn)
{
RModel.TAX = RModel.TAX + item.Split('=')[1];
}
You're adding strings, not numbers. You can use the TryParse method on for example the Int32 type to try convert a string to an int. The other numbers types have a similar TryParse method. If your number comes with extra signs, dots or commas, apply the the overload that accepts a FormatProvider matching the Numberstyle or a Culture the number is from.
string[] RegionalEarn = tickets["EARN"].ToString().Split(',');
var sum =0;
foreach (var item in RegionalEarn)
{
var num = 0;
if (Int32.TryParse(item.Split('=')[1], out num))
{
sum = sum + num;
}
else
{
// log error, item.Split('=')[1] is not an int
}
}
RModel.TAX = sum.ToString();
actually you done like concatenation.it comes only string values. so try convert to int or double .
string[] RegionalEarn = tickets["EARN"].ToString().Split(',');
foreach (var item in RegionalEarn)
{
RModel.TAX = Convert.ToInt32(RModel.TAX) + Convert.ToInt32( item.Split('=')[1]);
}
This is a simple way to do it.
string[] RegionalEarn = tickets["EARN"].ToString().Split(',');
foreach (var item in RegionalEarn)
{
RModel.TAX = (int.Parse(RModel.TAX) * item.Split('=').Sum (p => int.Parse(p))).ToString();
}
The above will take RModel.TAX multiply it with the sum of the values in the item array using Sum() method. This should give you the correct result.
I'm trying to automate the nested foreach provided that there is a Master List holding List of strings as items for the following scenario.
Here for example I have 5 list of strings held by a master list lstMaster
List<string> lst1 = new List<string> { "1", "2" };
List<string> lst2 = new List<string> { "-" };
List<string> lst3 = new List<string> { "Jan", "Feb" };
List<string> lst4 = new List<string> { "-" };
List<string> lst5 = new List<string> { "2014", "2015" };
List<List<string>> lstMaster = new List<List<string>> { lst1, lst2, lst3, lst4, lst5 };
List<string> lstRes = new List<string>();
foreach (var item1 in lst1)
{
foreach (var item2 in lst2)
{
foreach (var item3 in lst3)
{
foreach (var item4 in lst4)
{
foreach (var item5 in lst5)
{
lstRes.Add(item1 + item2 + item3 + item4 + item5);
}
}
}
}
}
I want to automate the below for loop regardless of the number of list items held by the master list lstMaster
Just do a cross-join with each successive list:
IEnumerable<string> lstRes = new List<string> {null};
foreach(var list in lstMaster)
{
// cross join the current result with each member of the next list
lstRes = lstRes.SelectMany(o => list.Select(s => o + s));
}
results:
List<String> (8 items)
------------------------
1-Jan-2014
1-Jan-2015
1-Feb-2014
1-Feb-2015
2-Jan-2014
2-Jan-2015
2-Feb-2014
2-Feb-2015
Notes:
Declaring lstRes as an IEnumerable<string> prevents the unnecessary creation of additional lists that will be thrown away
with each iteration
The instinctual null is used so that the first cross-join will have something to build on (with strings, null + s = s)
To make this truly dynamic you need two arrays of int loop variables (index and count):
int numLoops = lstMaster.Count;
int[] loopIndex = new int[numLoops];
int[] loopCnt = new int[numLoops];
Then you need the logic to iterate through all these loopIndexes.
Init to start value (optional)
for(int i = 0; i < numLoops; i++) loopIndex[i] = 0;
for(int i = 0; i < numLoops; i++) loopCnt[i] = lstMaster[i].Count;
Finally a big loop that works through all combinations.
bool finished = false;
while(!finished)
{
// access current element
string line = "";
for(int i = 0; i < numLoops; i++)
{
line += lstMaster[i][loopIndex[i]];
}
llstRes.Add(line);
int n = numLoops-1;
for(;;)
{
// increment innermost loop
loopIndex[n]++;
// if at Cnt: reset, increment outer loop
if(loopIndex[n] < loopCnt[n]) break;
loopIndex[n] = 0;
n--;
if(n < 0)
{
finished=true;
break;
}
}
}
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<IEnumerable<T>> lists)
{
IEnumerable<IEnumerable<T>> result = new List<IEnumerable<T>> { new List<T>() };
return lists.Aggregate(result, (current, list) => current.SelectMany(o => list.Select(s => o.Union(new[] { s }))));
}
var totalCombinations = 1;
foreach (var l in lstMaster)
{
totalCombinations *= l.Count == 0 ? 1 : l.Count;
}
var res = new string[totalCombinations];
for (int i = 0; i < lstMaster.Count; ++i)
{
var numOfEntries = totalCombinations / lstMaster[i].Count;
for (int j = 0; j < lstMaster[i].Count; ++j)
{
for (int k = numOfEntries * j; k < numOfEntries * (j + 1); ++k)
{
if (res[k] == null)
{
res[k] = lstMaster[i][j];
}
else
{
res[k] += lstMaster[i][j];
}
}
}
}
The algorithm starts from calculating how many combinations we need for all the sub lists.
When we know that we create a result array with exactly this number of entries. Then the algorithm iterates through all the sub lists, extract item from a sub list and calculates how many times the item should occur in the result and adds the item the specified number of times to the results. Moves to next item in the same list and adds to remaining fields (or as many as required if there is more than two items in the list). And it continues through all the sub lists and all the items.
One area though that needs improvement is when the list is empty. There is a risk of DivideByZeroException. I didn't add that. I'd prefer to focus on conveying the idea behind the calculations and didn't want to obfuscate it with additional checks.
I have the following method that calculates the top 20 numbers in a list and returns them.
static public List<int> CalculateTop20(List<int> nums)
{
List<int> Returned = new List<int>();
int count = nums.Count;
for (int j = 0; j < 20; j++)
{
var most = (from i in nums
group i by i into grp
orderby grp.Count() descending
select grp.Key).First();
Returned.Add(most);
nums.RemoveAll(item => item == most);
}
return Returned;
}
Except when I return them to main and try to output them to console they just come up as : System.Collections.Generic.List'1[System.Int32]...
I have multiple other methods passing lists throughout the program but this is the only one that is giving me this issue. Also when I output them right there while they're calculated the numbers are correct.
If you're just calling Console.WriteLine() on the result that's all you'll get, it just calls ToString() on the object which prints the type name.
If you want to output the list you'll need to do something like this:
foreach(var i in list) {
Console.WriteLine(i);
}
If you want the top 20 items from a List why not use LINQ?
// A sample list with 100 integers
var list = new List<int>();
for (var i = 0; i < 100; i++)
{
list.Add(i);
}
// Get the top 20
var top20 = list.OrderByDescending(x => x).Take(20);
Edit:
// Get the top 20 distinct values
var top20 = list.Distinct().OrderByDescending(x => x).Take(20);