Get the count of values from a dictionary C# - c#

I have a Dictionary which has an ID as the key and a list of lists as the value. I would like to get the count of how many lists are inside the list. This appears to give the correct value when I query it whilst debugging but when I go to try and access that data it only gives a count of 1 rather than 2. I'm sure it's something I'm missing but I can't put my finger on it.
Here's the count when I check it through debugging:
And here's it when I try to access that count of 2:
The whole method is:
public static List<string> getStatisticsCSVHeaders(List<Items> itemList, Dictionary<int, List<List<Statistic>>> availableStats)
{
List<string> topRow = new List<string>();
for (int i = 0; i < availableStats.Values.Count; i++)
{
topRow.Add("Phase " + (i+1));
for (int k = 0; k < itemList.Count; k++)
topRow.Add(getMetricHeader(itemList[k], true));
}
return topRow;
}
I'd like to have the number of lists inside my list as the counter for the line i < availableStats.Values.Count.
EDIT:
I should mention I've tried availableStats.Values[0].Count but this won't compile.

Debugger shows that you have a single item in your dictionary, and that item is a list with 2 elements. Because your code is taking the count of item in the dictionary you're getting 1.
To get the number of all the items in all the lists in that dictionary, try LINQ and Sum:
availableStats.Values.Sum(x => x.Count)

In your question, because value contains a list, so it is possible that it may contain a null value, so it is necessary to do a null check for values otherwise you can get an error inside your LINQ query.
var totalCount = availableStats.Values.Sum(x => x==null? 0 : x.Count);
There is one more way to get same result as follows:
var totalCount = availableStats.Sum(x => x.Value==null? 0 : x.Value.Count);

Related

How can I add an List with different data after loop beside existing list?

so bassicly I've got 2 different List
List<string> result = new List<string>;
List<string> outputs= new List<string>;
the outputs List getting filled in an loop and after the loop ends it will add the outputs list in the result list.
So that outputs will have this different values after the loop ends.
For example after the first loop ends the output list has data like:
exampleData1
exampleData2
exampleData3
and so on
so that the result List would now have this three example data.
Now the loop will hit again and will load different data like:
exampleData1.1
exampleData2.1
exampleData3.1
and now It should add this three example data to the result list:
so that now the result list should look like that:
exampleData1, exampleData1.1
exampleData2, exampleData2.1
exampleData3, exampleData3.1
and so should It go on after each loop after the output list changed it should be add side by side like one string.
I have tried things like that:
foreach (var (item1, item2) in output.Zip(output, (xo, y) => (xo, y)))
result.Add($" {item1}, {item2}");
but that's only adding the existing list side by side so that I have 2x the same value side by side.
I hope I have explained it understandable and if not, pls let me know.
Zip is good idea, but care. From the documentation :
If the sequences do not have the same number of elements, the method merges sequences until it reaches the end of one of them.
As result is empty, the end is reached before to start. The solution is to complete with the elements not iterated by Zip :
result = result.Zip(outputs, (r, o) => r + ", " + o)
.Union(result.Skip(outputs.Count)) // Add element from result not iterated by Zip
.Union(outputs.Skip(result.Count)) // Add element from outputs not iterated by Zip
.ToList();
Have look at this: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.zip?view=net-7.0 I think you have a mistake in your code. You're "zipping" outputs with outputs (i.e. itself) you need to zip it with result.
var mergedLists = result.Zip(outputs, (first, second) => first + " " + second);
UPDATED
Here's a full console app solution:
List<string> result = new();
for (var i = 0; i < 3; i++)
{
List<string> outputs = new();
for (var j = 0; j < 3; j++)
{
outputs.Add($"TestData{i}.{j}");
}
if (!result.Any())
{
result = outputs.ToList();
}
else
{
result = result.Zip(outputs, (first, second) => first + " " + second).ToList();
}
}
Console.WriteLine(string.Join(Environment.NewLine, result));
Console.ReadLine();

Loop through list of strings to find different values

I have a list that is populated with different values:
e.g
{GBP, GBP, GBP, USD}
so far I have this:
List<string> currencyTypes = new List<string>();
for (int i = 0; i < currencyTypes.Count; i++)
{
if currencyTypes[i] != [i]
console.writeline("currencies are different");
}
So if the list has all the same entries, the if statement shouldnt fire
e,g {GBP, GBP, GBP, GBP}
however if any of the values are different from the rest then the if statement should notice the difference and fire.
this doesnt work however.
any ideas?
You could use LINQ to test whether all entries are the same
if (currencyTypes.Distinct().Count() > 1) {
Console.WriteLine("currencies are different");
}
Slightly more efficient for long lists:
if (currencyTypes.Count > 1 && currencyTypes.Distinct().Skip(1).Any()) {
Console.WriteLine("currencies are different");
}
This is more efficient because Any iterates at most one element unlike Count which iterates the whole list.
First of all, your list is empty. Maybe it's for the sake of the example. If not, initialize it with data. However, modify line 3 and 5 to this to fix the problem.
for (int i = 1; i < currencyTypes.Count; i++)
{
if (currencyTypes[i] != currencyTypes[i-1])
....
}
you should first group your data and find your result depending the group.
eg
List<string> currencyTypes = new List<string>() {"USD", "GBP", "GBP", "GBP" };
// group list items
var typeGroup = currencyTypes.GroupBy(t => t);
if (typeGroup.Count() > 1)
Console.WriteLine("currencies are different");
// .
// .
// also you can check what item is unique
foreach (var t in typeGroup.Where(g => g.Count() == 1 ))
{
Console.WriteLine($"{t.Single()} is different");
}

Combine two List in C# using For Each

I have two list objects in c# as mentioned below
List A
[0]
Count="0",
CountType="0",
InvTpeCode="DLX"
[1]
Count="0",
CountType="0"
InvTpeCode="STD"
List B
[0]
Count="2",
CountType="17"
[1]
Count="12",
CountType="14"
I have tried using foreach to update list a value with list b values but unfortunately i am not able to bring the desired output.
Note : Both the list are of same size only
Instead of for-loop you can also use Zip
var result = A.Zip(B, (a, b) => new Item {
InvTpeCode = a.InvTpeCode,
CountType = b.CountType,
Count = b.Count });
If the lists are the same size then a for loop will be enough:
for (int i=0; i< A.Count();i++)
{
A[i].Count = B[i].Count;
A[i].CountType = B.CountType;
}
a foreach-loop is unpractible here, i would do the following:
for(int i=0; i < A.Count(); i++)
{
A[i].Count = B[i].Count;
A[i].CountType = B[i].CountType;
}
But keep in mind this will die hard if List A is longer than B.
First assure that the lists are the same size.
var index = 0;
foreach ( ObjA itemA in listA) {
replaceValues(ObjA, listB[index]);
index++;
}
The method replaceValues should then replace the properties of ObjA with the properties of the item from listB (with the same position).
But I think it makes no sense to use an foreach here. A simple for-loop can be used - as you need the index of the current element anyway.

Compare one value to several possible list matches

I'm back to haunt your dreams! I'm working on comparing some values in a complex loop. List 1 is a list of questions/answers, List 2 is also a list of questions/answers. I want to compare List 1 to List 2 and have duplicates removed from List 1 before merging it with List 2. My problem is in the current seed data I have the two items in List 1 match against List 2, but only one is removed instead of both.
I've been at this a couple days and my head is ready to explode, so I hope I can find some help!
Here's code for you:
//Fetching questions/answers which do not have an attempt
//Get questions, which automatically pull associated answers thanks to the model
List<QuizQuestions> notTriedQuestions = await db.QuizQuestions.Where(x=>x.QuizID == report.QuizHeader.QuizID).ToListAsync();
//Compare to existing attempt data and remove duplicate questions
int i = 0;
while(i < notTriedQuestions.Count)
{
var originalAnswersCount = notTriedQuestions.ElementAt(i).QuizAnswers.Count;
int j = 0;
while(j < originalAnswersCount)
{
var comparedID = notTriedQuestions.ElementAt(i).QuizAnswers.ElementAt(j).AnswerID;
if (report.QuizHeader.QuizQuestions.Any(item => item.QuizAnswers.Any(x => x.AnswerID == comparedID)))
{
notTriedQuestions.RemoveAt(i);
//Trip while value and cause break out of loop, otherwise you result in a catch
j = originalAnswersCount;
}
else
{
j++;
}
}
i++;
}
//Add filtered list to master list
foreach (var item in notTriedQuestions)
{
report.QuizQuestions.Add(item);
}
Try List.Union It is meant for exactly this sort of thing.

Concurent foreach iteration of two list strings

Let's say I have two List<string>. These are populated from the results of reading a text file
List owner contains:
cross
jhill
bbroms
List assignee contains:
Chris Cross
Jack Hill
Bryan Broms
During the read from a SQL source (the SQL statement contains a join)... I would perform
if(sqlReader["projects.owner"] == "something in owner list" || sqlReader["assign.assignee"] == "something in assignee list")
{
// add this projects information to the primary results LIST
list_by_owner.Add(sqlReader["projects.owner"],sqlReader["projects.project_date_created"],sqlReader["projects.project_name"],sqlReader["projects.project_status"]);
// if the assignee is not null, add also to the secondary results LIST
// logic to determine if assign.assignee is null goes here
list_by_assignee.Add(sqlReader["assign.assignee"],sqlReader["projects.owner"],sqlReader["projects.project_date_created"],sqlReader["projects.project_name"],sqlReader["projects.project_status"]);
}
I do not want to end up using nested foreach.
The FOR loop would probably suffice. Someone had mentioned ZIP to me but wasn't sure if that would be a preferable route to go in my situation.
One loop to iterate through both lists (assuming both have same count):
for (int i = 0; i < alpha.Count; i++)
{
var itemAlpha = alpha[i] // <= your object of list alpha
var itemBeta = beta[i] // <= your object of list beta
//write your code here
}
From what you describe, you don't need to iterate at all.
This is what you need:
http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx
Usage:
if ((listAlpga.contains(resultA) || (listBeta.contains(resultA)) {
// do your operation
}
List Iteration will happen implicitly inside the contains method. And thats 2n comparisions, vs n*n for nested iteration.
You would be better off with sequential iteration in each list one after the other, if at all you need to go that route.
This list is maybe better represented as a List<KeyValuePair<string, string>> which would pair the two list values together in a single list.
There are several options for this. The least "painful" would be plain old for loop:
for (var index = 0; index < alpha.Count; index++)
{
var alphaItem = alpha[index];
var betaItem = beta[index];
// Do something.
}
Another interesting approach is using the indexed LINQ methods (but you need to remember they get evaluated lazily, you have to consume the resulting enumerable), for example:
alpha.Select((alphaItem, index) =>
{
var betaItem = beta[index];
// Do something
})
Or you can enumerate both collection if you use the enumerator directly:
using (var alphaEnumerator = alpha.GetEnumerator())
using (var betaEnumerator = beta.GetEnumerator())
{
while (alphaEnumerator.MoveNext() && betaEnumerator.MoveNext())
{
var alphaItem = alphaEnumerator.Current;
var betaItem = betaEnumerator.Current;
// Do something
}
}
Zip (if you need pairs) or Concat (if you need combined list) are possible options to iterate 2 lists at the same time.
I like doing something like this to enumerate over parallel lists:
int alphaCount = alpha.Count ;
int betaCount = beta.Count ;
int i = 0 ;
while ( i < alphaCount && i < betaCount )
{
var a = alpha[i] ;
bar b = beta[i] ;
// handle matched alpha/beta pairs
++i ;
}
while ( i < alphaCount )
{
var a = alpha[i] ;
// handle unmatched alphas
++i ;
}
while ( i < betaCount )
{
var b = beta[i] ;
// handle unmatched betas
++i ;
}

Categories

Resources