Issue passing a List<int> in C# - c#

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);

Related

Adding to List<string> but having trouble with the items getting added

I have 2 lists with 200 items in each.
List A contains the names of the products.
List B contains the prices of the products.
I have another list (List C) with 250 items inside which include names and prices of products.
Now, I am trying to compare the names of List A to see if they exist in List C and if they do I want to use the price in List C.
This is what I've tried so far:
foreach (var item in wiznzList)
{
for (int j = 0; j < nameList.Count; j++)
{
if (nameList[j] == item.ProductName)
{
wizNzPriceList.Add(item.Price);
}
else
{
wizNzPriceList.Add("No Product");
}
}
}
I want to go through the list of names and check if they exist in List C if they do I want to add the price from List C and if it doesn't exist I want it to write No Product.
So, in the end I want 3 lists with 200 items in each.
Instead, when I run this I get 10040000 items added into the list. Could someone please point me in the right direction.
If i understand your problem correctly (and the jury is out on that)
You could use ToDictionary and Select
var dict = products.ToDictionary(x => x.ProductName, x => x.Price);
var results = names.Select(x => dict.TryGetValue(x, out var value) ? value.ToString() : "No Product");
Note : You could use Any for O(n^2) time complexity. However, ToDictionary would be more efficient
I have found a code that does what you want it to do !
Object Product(string pName, float pPrice).
listA list of Products so you can store and change price.
listB list of float, not used.
list C list of Products with pName and pPrice.
The CompareA_With_C() method first checks for same products and if true put price of list C in listA and breaks out of inner loop.
The else if statement waits till the loop has gone through the whole of listC and if no pName match found, changes pName to "No Product" in listA.
Code :
void CompareA_With_C()
{
for (int i = 0; i < listA.Count; i++)
{
for (int j = 0; j < listC.Count; j++)
{
string a = listA[i].pName;
string c = listC[j].pName;
if (string.Equals(a, c))
{
listA[i].pPrice = listC[j].pPrice;
break;
}
else if (j == (listC.Count - 1))
{
listA[i].pName = "No Product";
listB[i] = 0.0f;
}
}
}
}
You can try to use LINQ and replace your inner loop with Any method.
foreach (var item in wiznzList)
{
if (nameList.Any(p => p == item.ProductName)
{
wizNzPriceList.Add(item.Price);
}
else
{
wizNzPriceList.Add("No Product");
}
}
I was able to solve my problem by using the code below, Thank you very much Crispi.
for (int i = 0; i < nameList.Count; i++)
{
for (int j = 0; j < wiznzList.Count; j++)
{
string a = nameList[i];
string c = wiznzList[j].ProductName;
if (string.Equals(a, c))
{
wizNzPriceList.Add(wiznzList[j].Price);
break;
}
else if (j == (wiznzList.Count - 1))
{
wizNzPriceList.Add("No Product");
}
}
}
I now get 200 results as required. Thank you everyone for your time.

Get listitems according to the index of another list

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 :-)
}
}
}

Add two values from two different Lists

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;
}

Recursive self join

I have table as below. I need to get all the manager id's for the user id provided.
userid managerid
10 1
9 10
6 9
2 6
4 1
If i pass 2 to my method I need to get 1,10,9 and 6. I have written the below query which will return only first level parent. I.e it will return only 6 & 9.
public List<int?> mymethod (int userId){
return (from e in mycontext.EmployeeManagers
join e1 in m_context.EmployeeManagers
on e.UserId equals e1.ManagerId
where e1.UserId == userId
select e1.ManagerId).AsQueryable().ToList()
}
How can I modify the query to return all the manager hirerachy?
please help.
You can not do this in a sinqle LINQ expression. You have to run this in a loop.
A better option is to do this in the database and then return the results to LINQ.
See:
Hierarchical data in Linq - options and performance
Fill a Recursive Data Structure from a Self-Referential Database Table
Linq-to-Sql: recursively get children
I would simply run a short loop like this (sorry for invalid capitalization, coded from scratch):
public List<Int> GetAllManagers(int userID)
{
var result = new List<int>();
int index = 0;
result.add(userID); // start with user (it will be removed later)
while (index < result.count)
{
var moreData = from e in mycontext.EmployeeManagers
where e.UserId == result[index];
select e.ManagerId;
foreach (int id in moreData)
if (result.indexOf(id)==-1)
result.add(id);
index++;
}
result.delete(0);
return result;
}
or recursevly
private void AddUniqueIds (List<int> elements, ref List<int> list)
{
foreach (int id in elements)
if (list.indexOf(id)==-1)
list.add(id);
}
public List<int> GetAllManagers(int userID)
{
var result = new List<int>();
var moreData = from e in mycontext.EmployeeManagers
where e.UserId == result[index];
select e.ManagerId;
foreach (int id in moreData)
AddUniqueIds(result, GetAllManagers(id));
return result;
}
You need to use different pattern.
Lets see that you get your query.
var query = myContext.EmployeeManagers
Then, you could join it however you want to
for(int = 0; i < 5; i++)
{
query = query.Join( ... ..., i, ... ); // Can't recall all
// the parameters right now.
}
And then just execute it:
var result = query.ToList();

Adding to a range of generic lists in c#

Anyone know of a way to add a value to a range of generic lists in c#?
I'm currently building up a large List<List<int>> and the whole process is taking too long and I'm trying to avoid using foreach loops and nested foreach loops in order to shave some time off.
Lets say I had 600 rows in a generic list. For each of the first 200 rows, I'd like to add a "1". For the next 200, I'd like to add a "2". For the next 200, I'd like to add a "3".
The way I'm doing that now, I have to loop through it 600 times and add each one individually, whereas what I'd like to do is loop through it 3 times and add the entries in bulk.
The code I was hoping for would be something like:
List<List<int>> idList = GetFullList(); //list contains 600 rows
int[] newItems = {1, 3, 5};
int count = 0;
int amountToAmend = 200;
foreach (int i in newItems)
{
//List<int> newID = new List<int>();
//newID.Add(i);
(idList.GetRange(count, amountToAmend)).Add(i);
count += amountToAmend;
}
Obviously this doesn't work, but hopefully you can see the kind of thing I'm going for. In my application I'm currently needing to do tens of thousands of unnecessary loops, when often less than 10 could feasibly do the job if the code exists!
UPDATE: I'm not sure I've explained this well, so just to clarify, here are the results I'm looking for here
If I have a list with 6 rows like so:
[6,7,8]
[5,6,7]
[6,4,8]
[2,4,7]
[5,1,7]
[9,3,5]
i know that I'd like to add a 1 to the first 3 rows and a 2 to the next 3 rows, so they would become:
[6,7,8,1]
[5,6,7,1]
[6,4,8,1]
[2,4,7,2]
[5,1,7,2]
[9,3,5,2]
This is easy to do with foreach loops and is how I currently do it, but because of the sheer volume of data involved, I'm looking for ways to cut the time taken on specific functions. I'm not sure if a way exists tbh, but if anyone knows, then it'll be the good people of Stack Overflow :)
You may use Skip and Take methods from LINQ.
like idList.Skip(0).Take(200) it will give you first 200 items from your list, then you may update these items.
For update you may say:
int increment=2;
list.Select(intVal=> intVal+increment).ToList();
How about this:
foreach (int i in newItems)
{
foreach (var row in idList.Skip(count).Take(amountToAmend))
{
row.Add(i);
}
count += amountToAmend;
}
Or with a for-loop:
foreach (int i in newItems)
{
for (int j = 0; j < amountToAmend; j++)
{
idList[count + j].Add(i);
}
count += amountToAmend;
}
You want to have amountToAmend times each item in newItems ?
Like :
200 times 1
200 times 3
200 times 5
If so, you can try :
int amountToAmend = 200;
List<int> newItems = new List<int>(){ 1, 3, 5 };
<List<int>> idList = new List<List<int>>();
newItems.ForEach(i => idList.Add(new List<int>(Enumerable.Repeat(i, amountToAmend))));
List<List<int>> idList = GetFullList(); //list contains 600 rows
var iterator = idList.Begin();
int[] newItems = {1, 3, 5};
int count = 0;
int amountToAmend = 200;
foreach (var item in newItems)
{
iterator = iterator.AddItem(item);
iterator = iterator.MoveForward(amountToAmend);
}
public struct NestedListIterator<T>
{
public NestedListIterator(List<List<T>> lists, int listIndex, int itemIndex)
{
this.lists = lists;
this.ListIndex = listIndex;
this.ItemIndex = itemIndex;
}
public readonly int ListIndex;
public readonly int ItemIndex;
public readonly List<List<T>> lists;
public NestedListIterator<T> AddItem(T item)
{
var list = lists.ElementAtOrDefault(ListIndex);
if (list == null || list.Count < ItemIndex)
return this;//or throw new Exception(...)
list.Insert(ItemIndex, item);
return new NestedListIterator<T>(this.lists, this.ListIndex, this.ItemIndex + 1);
}
public NestedListIterator<T> MoveForward(List<List<T>> lists, int index)
{
//if (index < 0) throw new Exception(..)
var listIndex = this.ListIndex;
var itemIndex = this.ItemIndex + index;
for (; ; )
{
var list = lists.ElementAtOrDefault(ListIndex);
if (list == null)
return new NestedListIterator<T>(lists, listIndex, itemIndex);//or throw new Exception(...)
if (itemIndex <= list.Count)
return new NestedListIterator<T>(lists, listIndex, itemIndex);
itemIndex -= list.Count;
listIndex++;
}
}
public static int Compare(NestedListIterator<T> left, NestedListIterator<T> right)
{
var cmp = left.ListIndex.CompareTo(right.ListIndex);
if (cmp != 0)
return cmp;
return left.ItemIndex.CompareTo(right.ItemIndex);
}
public static bool operator <(NestedListIterator<T> left, NestedListIterator<T> right)
{
return Compare(left, right) < 0;
}
public static bool operator >(NestedListIterator<T> left, NestedListIterator<T> right)
{
return Compare(left, right) > 0;
}
}
public static class NestedListIteratorExtension
{
public static NestedListIterator<T> Begin<T>(this List<List<T>> lists)
{
return new NestedListIterator<T>(lists, 0, 0);
}
public static NestedListIterator<T> End<T>(this List<List<T>> lists)
{
return new NestedListIterator<T>(lists, lists.Count, 0);
}
}
There is no builtin function, although you cannot avoid looping(explicit or implicit) at all since you want to add a new element to every list.
You could combine List.GetRange with List.ForEach:
var newItems = new[] { 1, 2 };
int numPerGroup = (int)(idList.Count / newItems.Length);
for (int i = 0; i < newItems.Length; i++)
idList.GetRange(i * numPerGroup, numPerGroup)
.ForEach(l => l.Add(newItems[i]));
Note that above is not Linq and would work even in .NET 2.0
This is my old approach which was not what you needed:
You can use Linq and Enumerable.GroupBy to redistribute a flat list into nested lists:
int amountToAmend = 200;
// create sample data with 600 integers
List<int> flattened = Enumerable.Range(1, 600).ToList();
// group these 600 numbers into 3 nested lists with each 200 integers
List<List<int>> unflattened = flattened
.Select((i, index) => new { i, index })
.GroupBy(x => x.index / amountToAmend)
.Select(g => g.Select(x => x.i).ToList())
.ToList();
Here's the demo: http://ideone.com/LlEe2

Categories